Inspiré par la série de questions 'Caractéristiques cachées de ...', je suis curieux d'entendre parler de vos conseils préférés Django ou des fonctionnalités moins connues mais utiles que vous connaissez.
Je vais juste commencer par un conseil de moi :)
Utilisez os.path.dirname () dans settings.py pour éviter les noms de répertoire codés en dur.
Ne codez pas le chemin d'accès dans votre fichier settings.py si vous souhaitez exécuter votre projet dans des emplacements différents. Utilisez le code suivant dans settings.py si vos modèles et fichiers statiques sont situés dans le répertoire Django project:
# settings.py
import os
PROJECT_DIR = os.path.dirname(__file__)
...
STATIC_DOC_ROOT = os.path.join(PROJECT_DIR, "static")
...
TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, "templates"),
)
Crédits: J'ai eu cette astuce du screencast ' Django From The Ground Up '.
Installez Extensions de commande Django et pygraphviz , puis lancez la commande suivante pour obtenir une apparence vraiment agréable Django:
./manage.py graph_models -a -g -o my_project.png
Utilisez Django-ennoying'srender_to
décorateur au lieu de render_to_response
.
@render_to('template.html')
def foo(request):
bars = Bar.objects.all()
if request.user.is_authenticated():
return HttpResponseRedirect("/some/url/")
else:
return {'bars': bars}
# equals to
def foo(request):
bars = Bar.objects.all()
if request.user.is_authenticated():
return HttpResponseRedirect("/some/url/")
else:
return render_to_response('template.html',
{'bars': bars},
context_instance=RequestContext(request))
Modifié pour indiquer que le renvoi d'une réponse HttpResponse (telle qu'une redirection) court-circuitera le décorateur et fonctionnera comme vous le souhaitez.
J'utilise un ensemble de balises personnalisées sur tous les modèles de mon site. À la recherche d'un moyen de charger automatiquement le fichier (DRY, rappelez-vous?), J'ai trouvé ce qui suit:
from Django import template
template.add_to_builtins('project.app.templatetags.custom_tag_module')
Si vous mettez cela dans un module chargé par défaut (votre urlconf principal par exemple), les balises et filtres de votre module de balises personnalisées sont disponibles dans tous les modèles, sans utiliser {% load custom_tag_module %}
.
L'argument passé à template.add_to_builtins()
peut être n'importe quel chemin de module; votre module de balise personnalisé ne doit pas nécessairement vivre dans une application spécifique. Par exemple, il peut également s'agir d'un module dans le répertoire racine de votre projet (par exemple. 'project.custom_tag_module'
).
Virtualenv + Python = économiseur de vie si vous travaillez sur plusieurs Django projets et il est possible qu'ils ne le fassent pas tous). dépendent de la même version de Django/une application.
Ne codez pas vos URL en dur!
Utilisez noms d'URL à la place et la fonction reverse
pour obtenir l'URL elle-même.
Lorsque vous définissez vos mappages d'URL, donnez des noms à vos URL.
urlpatterns += ('project.application.views'
url( r'^something/$', 'view_function', name="url-name" ),
....
)
Assurez-vous que le nom est unique par URL.
J'ai généralement un format cohérent "project-appplication-view", par exemple. "cbx-forum-thread" pour une vue de fil.
[~ # ~] met à jour [~ # ~] (vole sans vergogne ajout d'ayaz ):
Ce nom peut être utilisé dans les modèles avec la balise url
.
Utilisez barre d’outils de débogage de Django . Par exemple, cela permet d'afficher toutes les requêtes SQL effectuées lors du rendu, mais vous pouvez également afficher la trace de pile pour chacune d'entre elles.
N'écrivez pas vos propres pages de connexion. Si vous utilisez Django.contrib.auth.
Le vrai secret est que si vous utilisez également Django.contrib.admin et Django.template.loaders.app_directories.load_template_source se trouve dans vos chargeurs de modèles, vous pouvez également obtenir vos modèles gratuitement!
# somewhere in urls.py
urlpatterns += patterns('Django.contrib.auth',
(r'^accounts/login/$','views.login', {'template_name': 'admin/login.html'}),
(r'^accounts/logout/$','views.logout'),
)
Supposons que vous avez un modèle d'utilisateur différent et que vous souhaitez l'inclure dans chaque réponse. Au lieu de faire ceci:
def myview(request, arg, arg2=None, template='my/template.html'):
''' My view... '''
response = dict()
myuser = MyUser.objects.get(user=request.user)
response['my_user'] = myuser
...
return render_to_response(template,
response,
context_instance=RequestContext(request))
Les processus de contexte vous permettent de transmettre n'importe quelle variable à vos modèles. Je mets généralement le mien dans 'my_project/apps/core/context.py
:
def my_context(request):
try:
return dict(my_user=MyUser.objects.get(user=request.user))
except ObjectNotFound:
return dict(my_user='')
Dans votre settings.py
ajouter la ligne suivante à votre TEMPLATE_CONTEXT_PROCESSORS
TEMPLATE_CONTEXT_PROCESSORS = (
'my_project.apps.core.context.my_context',
...
)
Maintenant, chaque fois qu'une demande est faite, elle inclut le my_user
touche automatiquement.
J'ai écrit un article à ce sujet il y a quelques mois sur mon blog, alors je vais simplement couper et coller:
Out of the box Django vous donne plusieurs signaux extrêmement utiles. Vous avez la possibilité de faire des choses avant et après l'enregistrement, l'initiation, la suppression ou même lorsqu'une demande est en cours de traitement. éloignez-vous des concepts et montrez comment ils sont utilisés. Supposons que nous avons un blog
from Django.utils.translation import ugettext_lazy as _
class Post(models.Model):
title = models.CharField(_('title'), max_length=255)
body = models.TextField(_('body'))
created = models.DateTimeField(auto_now_add=True)
Vous souhaitez donc notifier l’un des nombreux services de ping sur les blogs pour lesquels nous avons créé une nouvelle publication, reconstruire le cache des publications les plus récentes et envoyer un tweet à ce sujet. Avec les signaux, vous avez la possibilité de faire tout cela sans avoir à ajouter de méthodes à la classe Post.
import Twitter
from Django.core.cache import cache
from Django.db.models.signals import post_save
from Django.conf import settings
def posted_blog(sender, created=None, instance=None, **kwargs):
''' Listens for a blog post to save and alerts some services. '''
if (created and instance is not None):
Tweet = 'New blog post! %s' instance.title
t = Twitter.PostUpdate(settings.Twitter_USER,
settings.Twitter_PASSWD,
Tweet)
cache.set(instance.cache_key, instance, 60*5)
# send pingbacks
# ...
# whatever else
else:
cache.delete(instance.cache_key)
post_save.connect(posted_blog, sender=Post)
Voilà, en définissant cette fonction et en utilisant le signal post_init pour connecter la fonction au modèle Post et l'exécuter après son enregistrement.
Quand j'ai commencé, je ne savais pas qu'il y avait un Paginator , assurez-vous de connaître son existence !!
Utilisez IPython pour accéder à votre code à tout niveau et déboguer en utilisant la puissance d’IPython. Une fois que vous avez installé IPython, insérez ce code partout où vous souhaitez déboguer:
from IPython.Shell import IPShellEmbed; IPShellEmbed()()
Ensuite, actualisez la page, allez dans la fenêtre de votre serveur d'exécution et vous serez dans une fenêtre interactive IPython.
J'ai un extrait configuré dans TextMate, je viens donc de taper ipshell et d'appuyer sur tab. Je ne pourrais pas m'en passer.
Exécutez un serveur de développement SMTP qui produira tout ce qui lui est envoyé (si vous ne voulez pas installer réellement SMTP sur votre serveur dev.)
ligne de commande:
python -m smtpd -n -c DebuggingServer localhost:1025
Depuis le documentation Django-admin :
Si vous utilisez le shell Bash, envisagez d'installer le script d'achèvement Django bash, qui réside dans extras/Django_bash_completion
dans la distribution Django. Elle permet la complétion par des tabulations de Django-admin.py
et manage.py
commandes, afin que vous puissiez, par exemple ...
Django-admin.py
.sql
, puis [TAB], pour voir toutes les options disponibles dont le nom commence par sql
.La facilité ./manage.py runserver_plus
Fournie avec Django_extensions est vraiment géniale.
Il crée une page de débogage améliorée qui, entre autres choses, utilise le débogueur Werkzeug pour créer des consoles de débogage interactives pour chaque point de la pile (voir la capture d'écran). Il fournit également une méthode de débogage très utile dump()
pour afficher des informations sur un objet/cadre.
Pour installer, vous pouvez utiliser pip:
pip install Django_extensions
pip install Werkzeug
Ajoutez ensuite 'Django_extensions'
À votre INSTALLED_APPS
Tuple dans settings.py
Et démarrez le serveur de développement avec la nouvelle extension:
./manage.py runserver_plus
Cela changera la façon dont vous déboguez.
Lors de la tentative d’échange de données entre Django et une autre application, request.raw_post_data
est un bon ami. Utilisez-le pour recevoir et traiter de manière personnalisée, par exemple, des données XML.
Documentation: http://docs.djangoproject.com/en/dev/ref/request-response/
J'aime utiliser les projets Python du débogueur pdb pour déboguer Django.
Ceci est un lien utile pour apprendre à l'utiliser: http://www.ferg.org/papers/debugging_in_python.html
Ajouter assert False
dans votre code de vue pour vider les informations de débogage.
Utilisez Jinja2 aux côtés de Django.
Si vous trouvez que le Django est extrêmement restrictif (comme moi!), Vous n’aurez pas à vous en prendre à vous-même. Django est flexible, et le Le langage de modèle est vaguement couplé au reste du système. Il vous suffit donc de brancher un autre langage de modèle et de l'utiliser pour afficher vos réponses http!
J'utilise Jinja2 , c'est presque comme une version améliorée du langage de template Django, il utilise la même syntaxe et vous permet d'utiliser des expressions dans les instructions if! plus besoin de créer un if-tags personnalisé tel que if_item_in_list
! vous pouvez simplement dire %{ if item in list %}
, ou {% if object.field < 10 %}
.
Mais ce n'est pas tout; il a beaucoup plus de fonctionnalités pour faciliter la création de modèles, que je ne peux pas toutes les parcourir ici.
Cela ajoute à la réponse ci-dessus à propos de noms d'URL Django et distribution d'URL inverse .
Les noms d'URL peuvent également être utilisés efficacement dans les modèles. Par exemple, pour un modèle d'URL donné:
url(r'(?P<project_id>\d+)/team/$', 'project_team', name='project_team')
vous pouvez avoir les éléments suivants dans les modèles:
<a href="{% url project_team project.id %}">Team</a>
Étant donné que Django "les vues" doivent uniquement être des callables renvoyant une réponse HttpResponse, vous pouvez facilement créer des vues basées sur les classes telles que celles de Ruby sur Rails et d’autres frameworks.
Il y a plusieurs façons de créer des vues basées sur les classes, voici mon préféré:
from Django import http
class RestView(object):
methods = ('GET', 'HEAD')
@classmethod
def dispatch(cls, request, *args, **kwargs):
resource = cls()
if request.method.lower() not in (method.lower() for method in resource.methods):
return http.HttpResponseNotAllowed(resource.methods)
try:
method = getattr(resource, request.method.lower())
except AttributeError:
raise Exception("View method `%s` does not exist." % request.method.lower())
if not callable(method):
raise Exception("View method `%s` is not callable." % request.method.lower())
return method(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return http.HttpResponse()
def head(self, request, *args, **kwargs):
response = self.get(request, *args, **kwargs)
response.content = ''
return response
Vous pouvez ajouter toutes sortes d'autres choses, telles que le traitement conditionnel des demandes et l'autorisation, dans votre vue de base.
Une fois que vous avez configuré vos vues, votre urls.py ressemblera à ceci:
from Django.conf.urls.defaults import *
from views import MyRestView
urlpatterns = patterns('',
(r'^restview/', MyRestView.dispatch),
)
Au lieu d'utiliser render_to_response
Pour lier votre contexte à un modèle et le restituer (ce que montrent habituellement les documents Django), utilisez la vue générique direct_to_template
. Il fait la même chose que render_to_response
Mais ajoute automatiquement RequestContext au contexte du modèle, autorisant implicitement l'utilisation de processeurs de contexte. Vous pouvez le faire manuellement en utilisant render_to_response
, Mais pourquoi s'en préoccuper? C'est juste une autre étape à retenir et un autre LOC. En plus d'utiliser des processeurs de contexte, avoir RequestContext dans votre modèle vous permet de faire des choses comme:
<a href="{{MEDIA_URL}}images/frog.jpg">A frog</a>
ce qui est très utile. En fait, +1 sur les vues génériques en général. La documentation Django les affiche principalement sous forme de raccourcis pour ne même pas avoir de fichier views.py pour les applications simples, mais vous pouvez également les utiliser dans vos propres fonctions d'affichage:
from Django.views.generic import simple
def article_detail(request, slug=None):
article = get_object_or_404(Article, slug=slug)
return simple.direct_to_template(request,
template="articles/article_detail.html",
extra_context={'article': article}
)
Je n'ai pas assez de réputation pour répondre au commentaire en question, mais il est important de noter que si vous utilisez Jinja , il ne prend PAS en charge le caractère '-' dans les noms de blocs de modèles. , while while Django). Cela m’a causé beaucoup de problèmes et une perte de temps à essayer de retrouver le message d’erreur très obscur qu’il a généré.
Le Webdesign app est très utile pour commencer à concevoir votre site Web. Une fois importé, vous pouvez ajouter ceci pour générer un exemple de texte:
{% load webdesign %}
{% lorem 5 p %}
Django.db.models.get_model
vous permet de récupérer un modèle sans l'importer.
James montre à quel point cela peut être pratique: "Conseils Django: écrire de meilleurs modèles de balises - Itération 4" .
Tout le monde sait qu'il existe un serveur de développement que vous pouvez exécuter avec "manage.py runserver", mais saviez-vous qu'il existe également une vue de développement permettant de servir des fichiers statiques (CSS/JS/IMG)?
Les nouveaux arrivants sont toujours perplexes car Django ne fournit aucun moyen de servir des fichiers statiques. C’est parce que l’équipe de développeurs pense que c’est le travail d’un serveur Web réel.
Mais lors du développement, vous ne souhaitez peut-être pas configurer Apache + mod_wisgi, c'est lourd. Ensuite, vous pouvez simplement ajouter ce qui suit à urls.py:
(r'^site_media/(?P<path>.*)$', 'Django.views.static.serve',
{'document_root': '/path/to/media'}),
Votre CSS/JS/IMG sera disponible sur www.votresite.com/site_media/.
Bien sûr, ne l'utilisez pas dans un environnement de production.
J'ai appris celui-ci de la documentation de l'application sorl-thumbnails . Vous pouvez utiliser le mot clé "en tant que" dans les balises de modèle pour utiliser les résultats de l'appel ailleurs dans votre modèle.
Par exemple:
{% url image-processor uid as img_src %}
<img src="{% thumbnail img_src 100x100 %}"/>
Ceci est mentionné en passant dans la documentation de Django templatetag, mais en référence à des boucles uniquement. Ils ne vous disent pas que vous pouvez l’utiliser ailleurs (ailleurs?).
PyCharm IDE est un environnement agréable à coder et surtout à déboguer, avec support intégré pour Django.
Django.views.generic.list_detail.object_list - Il fournit toutes les variables de logique et de modèle pour la pagination (une de ces tâches fastidieuses que j'ai écrites mille fois maintenant). Envelopper permet n'importe quelle logique dont vous avez besoin. Ce petit bijou m'a évité de nombreuses heures d'erreurs de débogage une par une dans mes pages "Résultats de la recherche" et rend la vue plus propre.
Utilisez les migrations de base de données. Utilisez Sud .
Utilisez xml_models pour créer Django des modèles qui utilisent un XML REST API (au lieu d'un SQL)). C'est très utile. en particulier lorsque vous modélisez des API tierces - vous obtenez la même syntaxe QuerySet que celle à laquelle vous êtes habitué. Vous pouvez l’installer à partir de PyPI.
XML à partir d'une API:
<profile id=4>
<email>[email protected]</email>
<first_name>Joe</first_name>
<last_name>Example</last_name>
<date_of_birth>1975-05-15</date_of_birth>
</profile>
Et maintenant en python:
class Profile(xml_models.Model):
user_id = xml_models.IntField(xpath='/profile/@id')
email = xml_models.CharField(xpath='/profile/email')
first = xml_models.CharField(xpath='/profile/first_name')
last = xml_models.CharField(xpath='/profile/last_name')
birthday = xml_models.DateField(xpath='/profile/date_of_birth')
finders = {
(user_id,): settings.API_URL +'/api/v1/profile/userid/%s',
(email,): settings.API_URL +'/api/v1/profile/email/%s',
}
profile = Profile.objects.get(user_id=4)
print profile.email
# would print '[email protected]'
Il peut également gérer des relations et des collections. Nous l'utilisons tous les jours dans un code de production très utilisé, donc même s'il est en version bêta, il est très utilisable. Il contient également un bon nombre de stubs que vous pouvez utiliser dans vos tests.
(Avertissement: bien que je ne sois pas l'auteur de cette bibliothèque, je suis maintenant un committer, après avoir commis quelques commits mineurs)
Je viens de trouver ce lien: http://lincolnloop.com/Django-best-practices/#table-of-contents - "Meilleures pratiques de Django".
Au lieu d'évaluer tout le jeu de requêtes pour vérifier si vous avez obtenu des résultats, utilisez .exists () dans Django 1.2+ et .count () pour les versions précédentes.
Existe à la fois exist () et count () efface les clauses de commande d'ordre et récupère un entier de DB. Cependant, existe () retournera toujours 1 où nombre peut retourner des valeurs plus élevées sur lesquelles les limites seront appliquées manuellement. La source de has_result utilisée dans exist () et get_count utilisée dans count () pour les curieux.
Puisqu'ils renvoient tous les deux un seul entier, il n'y a pas d'instanciation de modèle, de chargement d'attributs de modèle en mémoire et pas de champs TextField importants échangés entre votre base de données et votre application.
Si vous avez déjà évalué la requête, .count () calcule len (cached_result) et .exists () calcule bool (cached_result)
Pas efficace - Exemple 1
books = Books.objects.filter(author__last_name='Brown')
if books:
# Do something
Pas efficace - Exemple 2
books = Books.objects.filter(author__last_name='Brown')
if len(books):
# Do something
Efficace - Exemple 1
books = Books.objects.filter(author__last_name='Brown')
if books.count():
# Do something
Efficace - Exemple 2
books = Books.objects.filter(author__last_name='Brown')
if books.exists():
# Do something
Si vous apportez des modifications au modèle
./manage.py dumpdata appname > appname_data.json
./manage.py reset appname
Django-admin.py loaddata appname_data.json
Utilisez signaux pour ajouter des méthodes d’accesseur à la volée.
J'ai vu cette technique dans Django-photologue : Pour tout objet Size ajouté, le signal post_init ajoutera les méthodes correspondantes au modèle Image. Si vous ajoutez un site géant , les méthodes permettant de récupérer l'image en résolution géante seront image.get_giant_url()
.
Les méthodes sont générées en appelant add_accessor_methods
du post_init
_ signal:
def add_accessor_methods(self, *args, **kwargs):
for size in PhotoSizeCache().sizes.keys():
setattr(self, 'get_%s_size' % size,
curry(self._get_SIZE_size, size=size))
setattr(self, 'get_%s_photosize' % size,
curry(self._get_SIZE_photosize, size=size))
setattr(self, 'get_%s_url' % size,
curry(self._get_SIZE_url, size=size))
setattr(self, 'get_%s_filename' % size,
curry(self._get_SIZE_filename, size=size))
Voir le code source de photologue.models pour une utilisation dans le monde réel.
Une chose que j'ai faite dans mon Django le site settings.py
charge les informations d’accès à la base de données depuis un fichier dans /etc
. De cette façon, la configuration de l'accès (hôte de la base de données, port, nom d'utilisateur, mot de passe) peut être différente pour chaque ordinateur et des informations sensibles telles que le mot de passe ne sont pas dans le référentiel de mon projet. Vous voudrez peut-être limiter l'accès aux travailleurs de la même manière, en leur permettant de se connecter avec un nom d'utilisateur différent.
Vous pouvez également transmettre les informations de connexion à la base de données, ou même simplement une clé ou un chemin d'accès à un fichier de configuration, via des variables d'environnement, et le gérer dans settings.py
.
Par exemple, voici comment j'insère mon fichier de configuration de base de données:
g = {}
dbSetup = {}
execfile(os.environ['DB_CONFIG'], g, dbSetup)
if 'databases' in dbSetup:
DATABASES = dbSetup['databases']
else:
DATABASES = {
'default': {
'ENGINE': 'Django.db.backends.mysql',
# ...
}
}
Inutile de dire que vous devez vous assurer que le fichier dans DB_CONFIG
_ n'est accessible à aucun utilisateur en dehors des administrateurs de la base de données et Django lui-même. Le cas par défaut devrait faire référence Django à la propre base de données de test d'un développeur. Il peut également être une meilleure solution en utilisant le module ast
au lieu de execfile
, mais je n'ai pas encore fait de recherches à ce sujet.
Une autre chose que je fais est d’utiliser des utilisateurs distincts pour les tâches d’administrateur de base de données par rapport à tout le reste. Dans mon manage.py
, J'ai ajouté le préambule suivant:
# Find a database configuration, if there is one, and set it in the environment.
adminDBConfFile = '/etc/Django/db_admin.py'
dbConfFile = '/etc/Django/db_regular.py'
import sys
import os
def goodFile(path):
return os.path.isfile(path) and os.access(path, os.R_OK)
if len(sys.argv) >= 2 and sys.argv[1] in ["syncdb", "dbshell", "migrate"] \
and goodFile(adminDBConfFile):
os.environ['DB_CONFIG'] = adminDBConfFile
Elif goodFile(dbConfFile):
os.environ['DB_CONFIG'] = dbConfFile
Où la config dans /etc/Django/db_regular.py
est destiné à un utilisateur n'ayant accès qu'à la base de données Django avec SELECT, INSERT, UPDATE et DELETE et /etc/Django/db_admin.py
est destiné à un utilisateur disposant de ces autorisations, plus CREATE, DROP, INDEX, ALTER et LOCK TABLES. (La commande migrate
provient de South .) Cela me protège un peu du code Django qui dérange mon schéma au moment de l'exécution et limite les dégâts une attaque par injection SQL peut provoquer (bien que vous deviez quand même vérifier et filtrer toutes les entrées utilisateur).
(Copié de ma réponse à ne autre question )
Au lieu d’exécuter le Django dev sur localhost, exécutez-le sur une interface réseau appropriée. Par exemple:
python manage.py runserver 192.168.1.110:8000
ou
python manage.py runserver 0.0.0.0:8000
Ensuite, vous pouvez non seulement utiliser facilement Fiddler ( http://www.fiddler2.com/fiddler2/ ) ou un autre outil comme HTTP Debugger ( http://www.httpdebugger.com/ ) pour inspecter vos en-têtes HTTP, mais vous pouvez également accéder à votre site de développement à partir d’autres machines de votre réseau local à tester.
Assurez-vous cependant que vous êtes protégé par un pare-feu, bien que le serveur dev soit minimal et relativement sûr.
Le Django Debug Toolbar est vraiment fantastique. Ce n'est pas vraiment une barre d'outils, mais un volet latéral qui vous indique toutes sortes d'informations sur ce qui vous a amené à la page que vous consultez - requêtes DB, variables de contexte envoyées au modèle, signaux, etc.
Utilisez wraps
decorator dans les vues personnalisées pour conserver le nom, le module et la docstring de la vue. Par exemple.
try:
from functools import wraps
except ImportError:
from Django.utils.functional import wraps # Python 2.3, 2.4 fallback.
def view_decorator(fun):
@wraps(fun)
def wrapper():
# here goes your decorator's code
return wrapper
Attention: ne fonctionnera pas sur les vues basées sur les classes (celles avec __call__
méthode)), si l'auteur n'a pas défini de __name__
propriété. Pour contourner ce problème, utilisez:
from Django.utils.decorators import available_attrs
...
@wraps(fun, assigned=available_attrs(fun))
Utilisation d'un dossier 'apps' pour organiser vos applications sans modifier PYTHONPATH
Cela m'a été utile lorsque je souhaite organiser mes dossiers de la manière suivante:
apps/
foo/
bar/
site/
settings.py
urls.py
sans écraser PYTHONPATH ni avoir à ajouter des applications à chaque import, comme par exemple:
from apps.foo.model import *
from apps.bar.forms import *
Dans votre settings.py ajouter
import os
import sys
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))
et vous êtes prêt à partir :-)
J'ai vu cela à http://codespatter.com/2009/04/10/how-to-add-locations-to-python-path-for-reusable-Django-apps/
Rendu formulaire via Django au lieu de as_ (ul | table | p) () .
Cet article explique comment utiliser un modèle pour rendre CusstomForms au lieu de as_p()
, as_table()
...
Pour que ça marche change
from Django import newforms as forms
à from Django import forms
from Django.newforms.forms import BoundField
à from Django.forms.forms import BoundField
Définir automatiquement l'attribut 'DEBUG' sur l'environnement de production (settings.py)
import socket
if socket.gethostname() == 'productionserver.com':
DEBUG = False
else:
DEBUG = True
Utilisez djangorecipe pour gérer votre projet
Pour commencer, voici tout ce que vous avez à faire:
Créez un fichier buildout.cfg avec le contenu suivant:
[buildout]
parts=Django
[Django]
recipe=djangorecipe
version=1.1.1
project=my_new_site
settings=development
python bootstrap.py
(ou python bootstrap_dev.py
_ si vous voulez utiliser distribuer)../bin/buildout
C'est ça. Vous devriez maintenant avoir un nouveau dossier "my_new_site", qui est votre nouveau projet Django 1.1.1, et dans ./bin vous trouverez le script Django
- qui remplace le manage.py sur une installation normale.
Quel est l'avantage? Supposons que vous souhaitiez utiliser quelque chose comme Django-comment-spamfighter dans votre projet. Tout ce que vous avez à faire est de changer votre buildout.cfg en quelque chose comme ceci:
[buildout]
parts=Django
[Django]
recipe=djangorecipe
version=1.1.1
project=my_new_site
settings=development
eggs=
Django-comments-spamfighter==0.4
Notez que tout ce que j’ai fait, c’est d’ajouter les 2 dernières lignes qui indiquent que la partie Django devrait également avoir le paquet Django-comments-spamfighter dans la version 0.4. La prochaine fois que vous exécutez ./bin/buildout
, buildout téléchargera ce paquet et modifiera ./bin/Django pour l’ajouter à son PYTHONPATH.
djangorecipe est également adapté au déploiement de votre projet avec mod_wsgi. Ajoutez simplement le wsgi=true
définissant la partie Django de votre buildout.cfg et un "Django.wsgi" apparaîtra dans votre dossier ./bin :-)
Et si vous définissez l'option test
sur une liste d'applications, djangorecipe créera un wrapper Nice qui exécutera tous les tests de l'application répertoriée dans votre projet.
Si vous souhaitez développer une seule application dans un environnement autonome pour le débogage, etc., Jakob Kaplan-Moss propose un didacticiel assez complet sur son blog
Utilisez reverse dans votre urlconf.
C'est l'une de ces astuces pour lesquelles je ne comprends pas pourquoi ce n'est pas le cas par défaut.
Voici un lien vers où je l'ai ramassé: http://andr.in/2009/11/21/calling-reverse-in-Django/
Voici l'extrait de code:
from Django.conf.urls.defaults import * from Django.core.urlresolvers import reverse from Django.utils.functional import lazy from Django.http import HttpResponse reverse_lazy = lazy(reverse, str) urlpatterns = patterns('', url(r'^comehere/', lambda request: HttpResponse('Welcome!'), name='comehere'), url(r'^$', 'Django.views.generic.simple.redirect_to', {'url': reverse_lazy('comehere')}, name='root') )
C’est un moyen très simple de ne plus jamais avoir à importer un autre de vos modèles dans votre python Shell.
Commencez par installer IPython (Si vous n'utilisez pas IPython, qu'est-ce qui ne va pas avec vous?). Ensuite, créez un script python, ipythonrc.py, dans votre répertoire de projet Django, avec le code suivant:
from Django.db.models.loading import get_models
for m in get_models():
globals()[m.__name__] = m
#NOTE: if you have two models with the same name you'll only end up with one of them
Ensuite, dans votre fichier ~/.ipython/ipythonrc, insérez le code suivant dans la section "Fichiers Python à charger et à exécuter":
execfile /path/to/project/ipythonrc.py
Maintenant, chaque fois que vous démarrez IPython ou exécutez ./manage.py Shell
tous vos modèles seront déjà importés et prêts à être utilisés. Pas besoin d'importer un autre modèle à nouveau.
Vous pouvez également mettre tout autre code que vous exécutez beaucoup dans votre fichier ipythonrc.py pour gagner du temps.
Changement Django propriétés du champ de formulaire sur init
Parfois, il est utile de passer des arguments supplémentaires à une classe Form.
from Django import forms
from mymodels import Group
class MyForm(forms.Form):
group=forms.ModelChoiceField(queryset=None)
email=forms.EmailField()
some_choices=forms.ChoiceField()
def __init__(self,my_var,*args,**kwrds):
super(MyForm,self).__init__(*args,**kwrds)
self.fields['group'].queryset=Group.objects.filter(...)
self.fields['email'].widget.attrs['size']='50'
self.fields['some_choices']=[[x,x] for x in list_of_stuff]
source: extraits de Dzone
Django_extensions
de https://github.com/Django-extensions/Django-extensions est tout simplement génial.
Peu de Nice ./manage.py
commandes:
Shell_plus
- auto-importe les modèles de tous les INSTALLED_APPSshow_urls
- imprime toutes les URL définies dans toutes les applications du projetrunscript
- exécute n'importe quel script dans le contexte du projet (vous pouvez utiliser des modèles et d'autres modules liés à Django)Utilisez des tâches asynchrones. Utilisez céleri
Lisez Django Unbreaking si ce n'est déjà fait. Il contient beaucoup d'informations utiles concernant les Django.
Créez des modèles dynamiques pour des ensembles de tables héritées ayant la même structure:
class BaseStructure(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Meta:
abstract=True
class DynamicTable(models.Model):
table_name = models.CharField(max_length=20)
def get_model(self):
class Meta:
managed=False
table_name=self.table_name
attrs = {}
attrs['Meta'] = Meta
# type(new_class_name, (base,classes), {extra: attributes})
dynamic_class = type(self.table_name, (BaseStructure,), attrs)
return dynamic_class
customers = DynamicTable.objects.get(table_name='Customers').get_model()
me = customers.objects.get(name='Josh Smeaton')
me.address = 'Over the Rainbow'
me.save()
Cela suppose que vous ayez des tables héritées ayant la même structure. Au lieu de créer un modèle pour envelopper chacune des tables, vous définissez un modèle de base et construisez de manière dynamique la classe nécessaire pour interagir avec une table spécifique.
Utilisez isapi-wsgi et Django-pyodbc pour exécuter Django sous Windows avec IIS et SQL Server !
Un peu tard pour la fête. Mais Django Canvas est récemment sorti et mérite une place ici.
Ne commencez pas votre projet avec Django-admin.py startproject
. Au lieu de cela, vous pouvez utiliser quelque chose comme Django Canvas pour vous aider à reconstituer un projet vierge avec les modules dont vous avez besoin.
Vous allez sur ce site, cochez quelques options puis téléchargez un projet vierge, si simple.
Il présente toutes les caractéristiques communes telles que les migrations de schéma South et les extensions de commande, ainsi que de nombreuses autres pratiques recommandées mentionnées ici. De plus, il a un grand start.sh/shart.bat
script qui installera python, virtualenv, pip, Django et tout ce dont vous avez besoin pour démarrer à partir d’une nouvelle copie de Windows, osx ou linux.
Django n'a pas de paramètres d'application, j'ai donc créé ma propre détection app_settings.py. Au bas de la settings.py j'ai ajouté ce code:
import sys, os
# Append application settings without triggering the __init__.
for installed_app in INSTALLED_APPS:
# Ignore Django applications
if not installed_app.startswith('Django.'):
# Find the app (and the settings file)
for path in sys.path:
path = os.path.join(path, installed_app, 'app_settings.py')
if os.path.isfile(path):
# Application settings found
exec open(path).read()
Il détecte app_settings.py dans tous les INSTALLED_APPS. Au lieu de l'importer, il lira le contenu du fichier app_settings et l'exécutera en ligne. Si app_settings est importé directement, toutes les sortes de Django seront générées (car Django n'est pas encore initialisé).).
Donc, mon application/app_settings.py ressemblera à ceci:
MIDDLEWARE_CLASSES += (
'app.middleware.FancyMiddleware',
)
Désormais, il suffit d’ajouter l’application à INSTALLED_APPS au lieu de rechercher tous les paramètres de l’application et de les ajouter à settings.py (middleware, urls ...).
Remarque: Il serait préférable que Django dispose d'un point d'ancrage pour ajouter des paramètres supplémentaires, afin que les paramètres de l'application puissent être ajoutés au démarrage (ou à l'exécution).
Lorsque vous passez des variables d'une vue à un modèle, la saisie du dictionnaire de réponses peut s'avérer fastidieuse. Je trouve ça agréable de simplement passer toutes les variables locales en même temps en utilisant locals()
.
def show_thing(request, thing_id):
thing = Thing.objects.get(pk=thing_id)
return render_to_response('templates/things/show.html', locals())
(Ce n'est pas une fonctionnalité cachée en soi, mais néanmoins utile quand on découvre Python et ou Django.)
Edit: Évidemment, il vaut mieux être explicite qu'implicite, mais cette approche peut être utile pendant le développement.
dir () & augmenter ValueError ()
Pour déboguer/explorer l'état des choses pendant le développement, j'utilise l'astuce suivante:
...
to_see = dir(inspect_this_thing)
to_see2 = inspect_this_thing.some_attribute
raise ValueError("Debugging")
...
Ceci est particulièrement utile lorsque vous travaillez sur des parties de Django qui ne sont pas particulièrement bien documentées (form.changed_fields en est un que j'ai utilisé récemment).
locals ().
Au lieu d'écrire chaque variable pour le contexte du modèle, utilisez la commande python builtin locals () qui crée un dictionnaire pour vous:
#This is tedious and not very DRY
return render_to_response('template.html', {"var1": var1, "var2":var2}, context_instance=RequestContext(request))
#95% of the time this works perfectly
return render_to_response('template.html', locals(), context_instance=RequestContext(request))
#The other 4.99%
render_dict = locals()
render_dict['also_needs'] = "this value"
return render_to_response('template.html', render_dict, context_instance=RequestContext(request))