PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Django cache illimité sur filesystem – Overrider FileBasedCache

samedi 13 octobre 2012 à 16:00

Django propose plusieurs façons de mettre de son site en cache.
Un de nos site gourmant en pages commencait à saturer le cache en mémoire alors il a fallut le basculer sur le filesystem, oui mais Django et son backend filesystem par défaut autorise 300 entrées dans le cache, ensuite il va effacer les anciennes pour les remplacer par les nouvelles, etc…

On peut régler le nombre d’entrées avec l’option MAX_ENTRIES dans les settings mais que fait django derrière ?
Il va scanner votre répertoire de cache et compter tous les fichiers ! Niveau performance on a vu mieux !

Voici un petit patch qui consiste à bypasser le comptage des fichiers dans le cas où l’ont veut un cache “infini”, ce qui soulève un autre problème, ça va cacher jusqu’à qu’il n’y ait plus de pages à cacher ou que le disque sature :)

dans un fichier cache.py que vous mettez où vous voulez (moi dans libs par ex):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
    Override FileBasedCache to extend entries cache count.
    avoid scanning all cache dir to count entries.
 
"""
import os
from django.core.cache.backends.filebased import FileBasedCache
 
class CustomFileBasedCache(FileBasedCache):
 
    def _get_num_entries(self):
       count = 0
       if self._max_entries == 9999: return 0
       for _,_,files in os.walk(self._dir):
           count += len(files)
       return count
    _num_entries = property(_get_num_entries)

dans les settings rajoutez à votre backend filesystem le backend customisé “libs.cache.CustomFileBasedCache” et l’option MAX_ENTRIES à -1:

CACHE_DEFAULT_SECONDS = 3600
CACHES = {
   'default': {
       'BACKEND': 'redis_cache.RedisCache',
       'LOCATION': 'localhost:6379',
       'TIMEOUT': CACHE_DEFAULT_SECONDS,
   },
   'filesystem': {
       'BACKEND': 'libs.cache.CustomFileBasedCache',
       'LOCATION': '/var/tmp/django',
       'TIMEOUT': CACHE_DEFAULT_SECONDS,
       'OPTIONS': {
            'MAX_ENTRIES': 9999 # Set 9999 for unlimited cache
       }
   }
}

On évite du coup le os.walk de la méthode _get_num_entries qui dans le cas d’un grand nombre de fichiers en cache pourrait faire du mal à votre serveur.

A utiliser avec précaution car ça cache, ça cache, ça cache… :)

Arf, on avait laissé l’ancien formulaire de contact

jeudi 11 octobre 2012 à 17:53

Le lien vers l’ancien formulaire de contact était toujours accessible, et du coup on a reçu un mail depuis celui-ci, alors qu’on ne peut pas y répondre.

C’est bon, on l’a viré.

En attendant, voici le mail, et la réponse (je strip l’intro et la conclusion.):

Je viens de lire le post sur virtualenv+django et je me disais qu’il existe un moyen différent, oserais-je dire plus propre (pas sur la tête pitié …), de faire quasiment la même chose.

Je m’explique : je vois dans le script l’utilisation de workon, je ne me rappelle plus trop mais je crois que cette commande est amenée par virtualenvwrapper. Dans ce cas là, je voulais vous faire partager le contenu de quelques fichiers contenu dans mon dossier .virtualenvs.

Tout d’abord le fichier postactivate (hook fourni par virtualenvwrapper s’insérant après l’initialisation de l’environnement) :

PROJECT_PATH="$PROJECT_HOME"/"$env_name"
 
if [ -a "$PROJECT_PATH" ] ;then
    cd "$PROJECT_PATH"
fi

ce petit script permet de faire ce que tu décris dans le post, si jamais ton dossier contenant le projet ne se trouve pas à l’endroit défini par la variable d’environnement $PROJECT_HOME, il est possible d’overrider son comportement en modifiant PROJECT_PATH par le chemin que tu souhaite dans le fichier .virtualenvs/nom_de_l’environnement/bin/postactivate

Voili voilou et sinon pour encore me faire mousser (mais pas trop hein), je voulais juste vous faire partager un autre script que je place dans postmkproject :

echo "Create a django project y/n ?"
while true
do
    read INPUT
    case "$INPUT" in
        "y" )
            cd "$PROJECT_HOME"
            rm -r "$envname"
            pip install django
            django-admin.py startproject "$envname"
            cd "$envname"
            break
            ;;
        "n" )
            break
            ;;
    esac
done

En clair, ça demande à l’utilisateur si son projet sera un projet django, ça télécharge le framework via pip et cela créé directement le projet dans notre dossier PROJECT_HOME, en évitant d’avoir à créer un autre sous-dossier rien que pour notre application django.

Bonjour l’ami,

Merci de l’info. Comme tu vois, on l’a fait passer. Quand tu as un truc comme ça à mettre, utilise les commentaires, ça en fait profiter tout le monde !

@+

Un alias bash pour Django + virtualenv dont je ne peux plus me passer

mercredi 10 octobre 2012 à 15:57

Ce n’est pas subtil, ça veut dire que pour chaque projet on rajoute cette patate dans son .bashrc:

function nom_du_projet {
    workon nom_du_virtualenv;
    cd /chemin/vers/le/projet/django/;
    if [[ $# -ne 0 ]]; then
        ./manage.py $@
    fi
}

Mais du coup:

Aller dans le dossier du projet et activer le virtualenv:

nom_du_projet

Aller dans le dossier du projet et activer le virtualenv, et éxécuter une commande de manage.py:

nom_du_projet schemamigration app --auto

Et bien sur on peut toujours revenir dans le dossier précédent avec:

cd -

Django-quicky: l’abolition des préliminaires, par Sam et Max

mardi 9 octobre 2012 à 17:22

Max aime Bottle pour sa simplicité. J’aime Django pour sa puissance. Nous aimons tous les deux les jeux de mots graveleux à connotations sexuelles.

Ainsi est né django-quicky, une petite app qui permet de faire du routing et du rendering déclaratif en Django.

pip install django-quicky

Par toutes les routes

Vous avez envie d’un site, maintenant, tout de suite. Mais il faut créer l’urls.py, et les vues, et les mapper. Et jongler entre les deux fichiers.

Ou alors vous pouvez juste faire:

from django_quicky import routing
 
url, urlpatterns = routing()
 
 
@url('/une/regex/que/django/comprends')
def une_vue(request):
    ...
 
 
@url('/on/peut/cummuler/les/routes')
@url('/une/regex/que/django/comprends')
def une_vue(request):
    ...

Le résultat est parfaitement compatible (et mélangeable) avec le routing habituel de Django. Il suffit juste d’utiliser views.py à la place d’urls.py, par exemple dans URL_ROOT ou dans include().

Rien ne vaut une bonne renderette

Declarer sa vue, c’est comme les jupes, c’est de plus en plus court avec le temps qui passe (et la méthode render()). Mais on peut faire encore plus court, genre limite tanga:

from django_quicky import view
 
@view(render_to='template.html')
def une_vue(request):
    return {'truc': truc}
 
 
@view(render_to='json')
def une_vue_json(request):
    return {'truc': truc}

Dans la première vue, le dico est utilisé comme contexte pour faire le rendu du template. Dans la seconde vue, le dico est retourné sérialisé en JSON.

On change de position ?

Des fois vous êtes sur une bonne lancée, mais vous voudriez changer juste un truc. Et garder le code précédent bien sûr. C’est d’ailleurs pour ça qu’on nous vend les CBV, c’est tellement plus flexible !

Vous aimez la souplesse ? Voici de quoi mettre les chevilles très près des oreilles:

from django_quicky import view
 
@view(render_to='template.html')
def vue_commune(request):
    return {'stuff': stuff}
 
@vue_commune.post()
def vue_POST(request, context):
    # do more stuff
    return context
 
@vue_commune.ajax(render_to='json')
def vue_AJAX(request, context):
    return context

On a ici une seule et même vue. La première partie est rendue sous forme de template si on y arrive par une requête GET ordinaire. La seconde si c’est une requête POST. La troisième si c’est une requête en AJAX, avec rendering JSON en prime. Et les deux dernières récupèrent toujours le résultat de la première avant de s’exécuter, ce qui permet d’avoir le code en commun dans la première.

C’est sous licence zlib.

Do’s and dont’s du français abordant l’indigène anglophone

lundi 8 octobre 2012 à 14:56

Parler une langue, ce n’est pas juste se faire comprendre, c’est aussi éviter de dire des conneries. Dans le doute, fermez-là.

Pratiquer les séries de mots à sonorités similaires

Certains son, par exemple les différentes forment de i, nous sont peu familiers dans notre langue. Il est tentant de faire l’impasse dessus en se disant qu’un mauvaise accent n’est pas la fin du monde, mais malheureusement la mise en contexte sur laquelle vous compter pour être compris ne va pas forcément jouer en votre faveur :

Apprendre les exceptions de prononciation et les jeux de mots graveleux

Le ‘a’ se prononce ‘ai’, sauf dans certains cas arbitraires (parfois pour mettre l’emphase sur l’origine française). “Massage” se prononce à la pseudo-française (sinon ils comprendront “message”), tout comme rap (sinon “I love rap” va être compris comme “I love rape”, avec tout le potentielle de LOLatoire que ça implique). Bref, évitez le jeu de mot involontaire.

Dans le même ordre d’idée, regardez quelques séries débile, pour y apprendre des trucs dangereux à dire nonchalamment comme:

Apprendre les mots qui ont changé de significations

Il y a 30 ans, gay était un mot parfaitement anodin. Celui-ci est évident, mais sachez qu’il y en a beaucoup d’autres. Par exemple:

Vous avez compris le principe…

Ici, une série pour jeunes ados peut vous aider à vous mettre à jour.

Et bien entendu, assurez-vous que le mot que vous voulez utiliser soit le bon. Voici ce que donne Harry Potter quand on remplace le mot “wand” (baguette) par “wang” (bite):

“You have your mother’s eyes. It seems only yesterday she was in here herself, buying her first wang. Ten and a quarter inches long, swishy, made of willow. Nice wang for charm work.”
“Your father, on the other hand, favored a mahogany wang. Eleven inches. ”

[...]

Harry took the wang. He felt a sudden warmth in his fingers. He raised the wang above his head, brought it swishing down through the dusty air and a stream of red and gold sparks shot from the end like a firework, throwing dancing spots of light on to the walls

[...]

“Oh, move over,” Hermione snarled. She grabbed Harry’s wang, tapped the lock, and whispered, ‘Alohomora!”

[...]

He bent down and pulled his wang out of the troll’s nose. It was covered in what looked like lumpy gray glue.

[...]

He ran onto the field as you fell, waved his wang, and you sort of slowed down before you hit the ground. Then he whirled his wang at the dementors. Shot silver stuff at them.

[...]

Something silver-white, something enormous, erupted from the end of his wang

Then, with a sigh, he raised his wang and prodded the silvery substance with its tip.