受到"隐藏的......的特征"系列的启发,我很想知道你最喜欢的Django技巧或者你知道但鲜为人知但有用的功能.
请每个答案只包含一个提示.
添加Django版本要求(如果有).
Haes.. 222
我只想从自己的小贴士开始:)
在settings.py中使用os.path.dirname()来避免硬编码的dirnames.
如果要在不同位置运行项目,请不要在settings.py中对路径进行硬编码.如果模板和静态文件位于Django项目目录中,请在settings.py中使用以下代码:
# 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"), )
致谢:我从截屏视频' Django From the Ground Up ' 得到了这个提示.
我只想从自己的小贴士开始:)
在settings.py中使用os.path.dirname()来避免硬编码的dirnames.
如果要在不同位置运行项目,请不要在settings.py中对路径进行硬编码.如果模板和静态文件位于Django项目目录中,请在settings.py中使用以下代码:
# 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"), )
致谢:我从截屏视频' Django From the Ground Up ' 得到了这个提示.
安装Django Command Extensions和pygraphviz,然后发出以下命令以获得非常好看的Django模型可视化:
./manage.py graph_models -a -g -o my_project.png
使用django-annoying的 render_to
装饰器代替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))
编辑指出返回一个HttpResponse(如重定向)将使装饰器短路并按预期工作.
我在网站的模板上使用了一组自定义标签.正在寻找一种自动加载它的方法(干,记得吗?),我发现了以下内容:
from django import template template.add_to_builtins('project.app.templatetags.custom_tag_module')
如果你将它放在一个默认加载的模块中(例如你的主urlconf),你可以在任何模板中使用自定义标签模块中的标签和过滤器,而不使用{% load custom_tag_module %}
.
传递给的参数template.add_to_builtins()
可以是任何模块路径; 您的自定义标记模块不必存在于特定的应用程序中.例如,它也可以是项目根目录中的模块(例如'project.custom_tag_module'
).
如果您正在处理多个Django项目,并且有可能它们都不依赖于相同版本的Django /应用程序,那么Virtualenv + Python =生命保护程序.
不要硬编码您的网址!
改为使用url名称,以及reverse
获取URL本身的函数.
定义URL映射时,请为URL指定名称.
urlpatterns += ('project.application.views' url( r'^something/$', 'view_function', name="url-name" ), .... )
确保每个URL的名称唯一.
我通常有一个一致的格式"project-appplication-view",例如"cbx-forum-thread"用于线程视图.
更新(无耻地窃取ayaz的补充):
此名称可以在带有url
标记的模板中使用.
使用django调试工具栏.例如,它允许查看渲染视图时执行的所有SQL查询,您还可以查看其中任何一个的堆栈跟踪.
不要编写自己的登录页面.如果您正在使用django.contrib.auth.
真正的,肮脏的秘密是,如果您还使用django.contrib.admin,并且django.template.loaders.app_directories.load_template_source在您的模板加载器中, 您也可以免费获得模板!
# somewhere in urls.py urlpatterns += patterns('django.contrib.auth', (r'^accounts/login/$','views.login', {'template_name': 'admin/login.html'}), (r'^accounts/logout/$','views.logout'), )
假设您有不同的用户模型,并且希望在每个响应中包含该模型.而不是这样做:
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))
上下文进程使您能够将任何变量传递给模板.我通常把我的'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='')
在您的settings.py
添加中添加以下行TEMPLATE_CONTEXT_PROCESSORS
TEMPLATE_CONTEXT_PROCESSORS = ( 'my_project.apps.core.context.my_context', ... )
现在,每次发出请求时,它都会my_user
自动包含密钥.
几个月前我写了一篇关于这篇文章的博文,所以我只是剪切和粘贴:
开箱即用Django为您提供了几个非常有用的信号.您可以在保存,初始化,删除之前或之后执行操作,甚至可以在处理请求时执行操作.因此,让我们远离概念并演示如何使用这些概念.说我们有一个博客
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)
因此,不知何故,您想要通知我们发布新帖子的许多博客ping服务之一,重建最新的帖子缓存,并发布有关它的推文.有了信号,你就可以完成所有这些操作而无需向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)
我们通过定义该函数并使用post_init信号将函数连接到Post模型并在保存后执行它.
当我开始时,我不知道有一个Paginator,确保你知道它的存在!
使用IPython在任何级别跳转到您的代码并使用IPython的强大功能进行调试.一旦安装了IPython,只需将此代码放在要调试的任何位置:
from IPython.Shell import IPShellEmbed; IPShellEmbed()()
然后,刷新页面,转到runserver窗口,您将进入交互式IPython窗口.
我在TextMate中设置了一个代码段,所以我只需输入ipshell并点击tab.没有它我就活不下去.
运行开发SMTP服务器,只输出发送给它的任何内容(如果您不想在开发服务器上实际安装SMTP.)
命令行:
python -m smtpd -n -c DebuggingServer localhost:1025
从django-admin文档:
如果您使用Bash shell,请考虑安装Django bash完成脚本,该脚本extras/django_bash_completion
位于Django发行版中.它启用tab-completion django-admin.py
和manage.py
命令,所以你可以,例如......
类型django-admin.py
.
按[TAB]查看所有可用选项.
键入sql
,然后按[TAB],查看名称以其开头的所有可用选项sql
.
该./manage.py runserver_plus
附带facilty django_extensions是真正真棒.
它创建了一个增强的调试页面,除其他外,它使用Werkzeug调试器为堆栈中的每个点创建交互式调试控制台(参见屏幕截图).它还提供了一种非常有用的便利调试方法,dump()
用于显示有关对象/帧的信息.
要安装,您可以使用pip:
pip install django_extensions pip install Werkzeug
然后添加'django_extensions'
到您的INSTALLED_APPS
元组settings.py
并使用新扩展启动开发服务器:
./manage.py runserver_plus
这将改变您的调试方式.
我喜欢使用Python调试器pdb来调试Django项目.
这是学习如何使用它的有用链接:http://www.ferg.org/papers/debugging_in_python.html
当试图在Django和另一个应用程序之间交换数据时,request.raw_post_data
是一个好朋友.使用它来接收和自定义处理XML数据.
文档:http: //docs.djangoproject.com/en/dev/ref/request-response/
使用Jinja2和Django.
如果你发现Django模板语言受到极大限制(比如我!)那么你就不必坚持下去了.Django非常灵活,模板语言与系统的其他部分松散耦合,因此只需插入另一种模板语言并使用它来呈现您的http响应!
我使用Jinja2,它几乎就像是django模板语言的加电版本,它使用相同的语法,并允许你在if语句中使用表达式!没有更多的自定义if标签,如if_item_in_list
!你可以简单地说%{ if item in list %}
,或者{% if object.field < 10 %}
.
但那还不是全部; 它有更多的功能来简化模板创建,我不能在这里完成所有这些功能.
添加assert False
视图代码以转储调试信息.
这增加了上面关于Django URL名称和反向URL调度的回复.
URL名称也可以在模板中有效使用.例如,对于给定的URL模式:
url(r'(?P\d+)/team/$', 'project_team', name='project_team')
您可以在模板中包含以下内容:
Team
由于Django"views"只需要是返回HttpResponse的callables,因此您可以轻松地创建类似于Ruby on Rails和其他框架的基于类的视图.
有几种方法可以创建基于类的视图,这是我的最爱:
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
您可以在基本视图中添加各种其他内容,例如条件请求处理和授权.
一旦你获得了你的视图设置,你的urls.py将如下所示:
from django.conf.urls.defaults import * from views import MyRestView urlpatterns = patterns('', (r'^restview/', MyRestView.dispatch), )
而不是使用render_to_response
将上下文绑定到模板并呈现它(这是Django文档通常显示的内容),而不是使用通用视图direct_to_template
.它做了同样的事情,render_to_response
但它也自动将RequestContext添加到模板上下文,隐式允许使用上下文处理器.你可以手动使用render_to_response
,但为什么要这么麻烦?这只是记住另一个LOC的又一步.除了使用上下文处理器之外,在模板中使用RequestContext还可以执行以下操作:
A frog
这非常有用.实际上,一般来说,通用视图上的+1.Django文档主要将它们显示为甚至没有简单应用程序的views.py文件的快捷方式,但您也可以在自己的视图函数中使用它们:
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} )
我没有足够的声誉回复有问题的评论,但重要的是要注意,如果你打算使用Jinja,它不支持模板块名称中的' - '字符,而Django则支持. - '字符.这给我带来了很多问题,并且浪费时间试图追踪它生成的非常模糊的错误消息.
django.db.models.get_model
允许您在不导入模型的情况下检索模型.
James展示了它有多么方便:"Django提示:编写更好的模板标签 - 迭代4".
在网页设计应用程序开始设计你的网站时,是非常有用的.导入后,您可以添加此项以生成示例文本:
{% load webdesign %} {% lorem 5 p %}
大家都知道有一个可以用"manage.py runserver"运行的开发服务器,但是你知道有一个服务静态文件(CSS/JS/IMG)的开发视图吗?
新手总是感到困惑,因为Django没有任何方式来提供静态文件.这是因为开发团队认为它是现实生活中Web服务器的工作.
但是在开发时,你可能不想设置Apache + mod_wisgi,它很重.然后你可以将以下内容添加到urls.py:
(r'^site_media/(?P.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
您的CSS/JS/IMG将在www.yoursite.com/site_media/上提供.
当然,不要在生产环境中使用它.
我从sorl-thumbnails应用程序的文档中学到了这一点.您可以使用模板标记中的"as"关键字来使用模板中其他位置的调用结果.
例如:
{% url image-processor uid as img_src %}
这在Django templatetag文档中提到,但仅参考循环.他们并不是说你可以在其他地方(任何地方?)使用它.
django.views.generic.list_detail.object_list - 它提供了分页的所有逻辑和模板变量(其中一个我已经写过的那一千次现在的苦差事). 包装它允许您需要的任何逻辑.这个gem在我的"搜索结果"页面中为我节省了许多小时的调试错误,并使视图代码更加清晰.
PyCharm IDE是一个很好的代码,特别是调试环境,内置了对Django的支持.
使用xml_models创建使用XML REST API后端(而不是SQL后端)的Django模型.这在建模第三方API时非常有用 - 您可以获得与之相同的QuerySet语法.您可以从PyPI安装它.
来自API的XML:
joe@example.com Joe Example 1975-05-15
而现在在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 'joe@example.com'
它还可以处理关系和集合.我们每天都在大量使用的生产代码中使用它,所以即使它是beta版,它也非常实用.它还有一组很好的存根,可以在测试中使用.
(免责声明:虽然我不是这个库的作者,但我现在是一个提交者,做了一些小的提交)
使用数据库迁移.使用南.
刚刚找到这个链接:http://lincolnloop.com/django-best-practices/#table-of-contents - "Django Best Practices".
而不是评估整个查询集以检查是否有任何结果,在Django 1.2+和.count()中使用.exists()用于以前的版本.
exists()和count()都按子句清除顺序,并从DB中检索单个整数.但是,exists()将始终返回1,其中count可以返回更高的值,在该值上将手动应用限制.for ()中使用的has_result的源和用于好奇的count()中使用的get_count.
由于它们都返回一个整数,因此没有模型实例化,在内存中加载模型属性,并且在数据库和应用程序之间没有传递大的TextField.
如果您已经评估了查询,.count()计算len(cached_result)和.exists()计算bool(cached_result)
效率不高 - 例1
books = Books.objects.filter(author__last_name='Brown') if books: # Do something
效率不高 - 例2
books = Books.objects.filter(author__last_name='Brown') if len(books): # Do something
高效 - 例1
books = Books.objects.filter(author__last_name='Brown') if books.count(): # Do something
高效 - 例2
books = Books.objects.filter(author__last_name='Brown') if books.exists(): # Do something
如果您对模型进行更改
./manage.py dumpdata appname > appname_data.json ./manage.py reset appname django-admin.py loaddata appname_data.json
使用信号即时添加访问器方法.
我在django-photologue中看到了这种技术:对于添加的任何Size对象,post_init信号将相应的方法添加到Image模型中.如果添加一个站点巨人,那么以巨大分辨率检索图片的方法将是image.get_giant_url()
.
的方法是通过调用产生add_accessor_methods
从post_init
信号:
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))
有关实际使用情况,请参阅photologue.models的源代码.
我在Django网站上做的一件事settings.py
就是从文件中加载数据库访问信息/etc
.这样,每台计算机的访问设置(数据库主机,端口,用户名,密码)可能不同,而密码等敏感信息不在我项目的存储库中.您可能希望以类似的方式限制对工作人员的访问,方法是使用不同的用户名进行连接.
您还可以通过环境变量传递数据库连接信息,甚至只传递配置文件的密钥或路径,然后处理它settings.py
.
例如,以下是我如何提取数据库配置文件:
g = {} dbSetup = {} execfile(os.environ['DB_CONFIG'], g, dbSetup) if 'databases' in dbSetup: DATABASES = dbSetup['databases'] else: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # ... } }
不用说,您需要确保DB_CONFIG
除了db admin和Django本身之外的任何用户都无法访问该文件.默认情况下应该将Django引用到开发人员自己的测试数据库.使用该ast
模块可能还有更好的解决方案execfile
,但我还没有研究过它.
我做的另一件事是使用单独的用户进行数据库管理任务与其他任何事情.在我看来manage.py
,我添加了以下序言:
# 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
其中config in /etc/django/db_regular.py
适用于只能使用SELECT,INSERT,UPDATE和DELETE访问Django数据库/etc/django/db_admin.py
的用户,并且适用于具有这些权限的用户以及CREATE,DROP,INDEX,ALTER和LOCK TABLES.(该migrate
命令来自South.)这给了我一些保护,防止Django代码在运行时弄乱我的模式,并且它限制了SQL注入攻击可能造成的损害(尽管你仍然应该检查并过滤所有用户输入).
(复制自我对另一个问题的回答)
而不是在localhost上运行Django dev服务器,而是在适当的网络接口上运行它.例如:
python manage.py runserver 192.168.1.110:8000
要么
python manage.py runserver 0.0.0.0:8000
然后,您不仅可以轻松使用Fiddler(http://www.fiddler2.com/fiddler2/)或其他工具(如HTTP Debugger(http://www.httpdebugger.com/))来检查您的HTTP标头,还可以从LAN上的其他计算机访问您的开发站点进行测试.
尽管开发服务器很小且相对安全,但请确保您受到防火墙的保护.
wraps
在自定义视图装饰器中使用装饰器来保留视图的名称,模块和文档字符串.例如
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
注意:__call__
如果作者尚未定义__name__
属性,则不会对基于类的视图(具有方法定义的视图)起作用.作为解决方法使用:
from django.utils.decorators import available_attrs ... @wraps(fun, assigned=available_attrs(fun))
在Django的调试工具栏真是妙不可言.它实际上并不是一个工具栏,它实际上会显示一个侧窗,它会告诉您有关您正在查看的页面的所有信息 - 数据库查询,发送到模板的上下文变量,信号等等.
使用'apps'文件夹来组织您的应用程序而无需编辑PYTHONPATH
当我想像这样组织我的文件夹时,这很方便:
apps/ foo/ bar/ site/ settings.py urls.py
没有覆盖PYTHONPATH或必须为每个导入添加应用程序,如:
from apps.foo.model import * from apps.bar.forms import *
在您的settings.py中添加
import os import sys PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))
你准备好了:-)
我在http://codespatter.com/2009/04/10/how-to-add-locations-to-python-path-for-reusable-django-apps/看到了这个
通过django模板而不是as_(ul | table | p)()渲染表单.
本文介绍如何使用模板来渲染CusstomForms代替as_p()
,as_table()
...
使它改变工作
from django import newforms as forms
至 from django import forms
from django.newforms.forms import BoundField
至 from django.forms.forms import BoundField
使用djangorecipe来管理您的项目
如果你正在编写一个新的应用程序,这个配方使得在项目之外进行测试非常容易
它允许您管理项目的依赖项(例如,它应该依赖的某个应用程序版本)
你需要做的就是这个:
为您的新网站(或库)创建一个文件夹
创建一个buildout.cfg,其中包含以下内容:
[buildout] parts=django [django] recipe=djangorecipe version=1.1.1 project=my_new_site settings=development
获取bootstrap.py以获取buildout的本地安装并将其放在您的目录中.您可以选择正式的(抱歉,Markdown不喜欢完整链接的一部分: - /)或使用分配而不是setuptools的装置,如Reinout van Rees所述.
python bootstrap.py
(或者python bootstrap_dev.py
如果你想使用发布).
./bin/buildout
而已.您现在应该有一个新文件夹"my_new_site",这是您的新django 1.1.1项目,在./bin中,您将找到django
-script,它将替换正常安装中的manage.py.
有什么好处?假设您想在项目中使用django-comment-spamfighter之类的东西.您所要做的就是将buildout.cfg更改为以下内容:
[buildout] parts=django [django] recipe=djangorecipe version=1.1.1 project=my_new_site settings=development eggs= django-comments-spamfighter==0.4
请注意,我所做的只是添加最后两行,即django-part应该还有版本0.4中的django-comments-spamfighter包.下次运行时./bin/buildout
,buildout将下载该软件包并修改./bin/django以将其添加到PYTHONPATH.
djangorecipe也适合用mod_wsgi部署你的项目.只需将wsgi=true
设置添加到buildout.cfg的django-part中,"django.wsgi"将出现在./bin文件夹中:-)
如果将test
选项设置为应用程序列表,则djangorecipe将为您创建一个很好的包装器,它为项目中列出的应用程序运行所有测试.
如果您想在独立环境中开发单个应用程序以进行调试等,Jakob Kaplan-Moss在他的博客上有一个非常完整的教程
在urlconf中使用reverse.
这是其中一个技巧,我不明白为什么它不是默认值.
这是我选择它的地方的链接:http: //andr.in/2009/11/21/calling-reverse-in-django/
这是代码片段:
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') )
在生产环境中自动设置'DEBUG'属性(settings.py)
import socket if socket.gethostname() == 'productionserver.com': DEBUG = False else: DEBUG = True
通过:http://nicksergeant.com/2008/automatically-setting-debug-in-your-django-app-based-on-server-hostname/