【发布时间】:2010-10-07 17:30:31
【问题描述】:
受问题系列“...的隐藏功能”的启发,我很想知道您最喜欢的 Django 技巧或您知道的鲜为人知但有用的功能。
- 请在每个答案中只包含一个提示。
- 如果有,请添加 Django 版本要求。
【问题讨论】:
标签: python django hidden-features
受问题系列“...的隐藏功能”的启发,我很想知道您最喜欢的 Django 技巧或您知道的鲜为人知但有用的功能。
【问题讨论】:
标签: python django hidden-features
我只是从我自己的提示开始:)
在 settings.py 中使用 os.path.dirname() 来避免硬编码的目录名。
如果您想在不同的位置运行项目,请不要在 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”中得到了这个提示。
【讨论】:
j = lambda filename: os.path.join(PROJECT_DIR, filename)。然后你只需要输入j("static")。
wontfix 的决定。
安装 Django Command Extensions 和 pygraphviz 然后发出以下命令以获得非常漂亮的 Django 模型可视化:
./manage.py graph_models -a -g -o my_project.png
【讨论】:
使用django-annoying's 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(例如重定向)会使装饰器短路并按预期工作。
【讨论】:
我在整个网站的模板中都使用了一组自定义标签。寻找一种自动加载它的方法(DRY,记得吗?),我发现了以下内容:
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')。
【讨论】:
Virtualenv + Python = 如果您正在处理多个 Django 项目,并且它们有可能不依赖于同一版本的 Django/应用程序,则它们是救生员。
【讨论】:
virtualenv myNewEnv --no-site-packages; . myNewEnv/bin/activate; pip install django;它只是工作!
不要对您的网址进行硬编码!
改用url names,并使用reverse 函数来获取URL 本身。
定义 URL 映射时,为 URL 命名。
urlpatterns += ('project.application.views'
url( r'^something/$', 'view_function', name="url-name" ),
....
)
确保每个 URL 的名称都是唯一的。
我通常有一个一致的格式“项目-应用程序-视图”,例如"cbx-forum-thread" 用于线程视图。
更新(无耻盗用ayaz's addition):
此名称可用于带有url tag 的模板。
【讨论】:
url 标签……他的立场是,网址无论如何都不应该改变(如果你想对您的用户友好)。
{% url path.to.view.name arg1 arg2 %} docs.djangoproject.com/en/dev/ref/templates/builtins/…
reverse environment.filters['url'] = django.core.urlresolvers.reverse 并且您可以像这样在模板中使用它:{{ 'view-name'|url(arg1, arg2)|e }}(需要“e”来转义某些字符以包含在内在 HTML 中)
使用django debug toolbar。例如,它允许查看渲染视图时执行的所有 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 中设置了一个 sn-p,所以我只需键入 ipshell 并点击选项卡。没有它我活不下去。
【讨论】:
ipdb,然后输入ipdb.set_trace()
运行一个开发 SMTP 服务器,它只会输出发送给它的任何内容(如果您不想在开发服务器上实际安装 SMTP。)
命令行:
python -m smtpd -n -c DebuggingServer localhost:1025
【讨论】:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' ..将电子邮件打印到manage.py 输出。
如果您使用 Bash shell,请考虑安装 Django bash 完成脚本,该脚本位于 Django 发行版的 extras/django_bash_completion 中。它启用了django-admin.py 和manage.py 命令的制表符补全功能,例如,您可以...
django-admin.py。sql,然后输入[TAB],查看名称以sql开头的所有可用选项。【讨论】:
django_extensions 附带的./manage.py runserver_plus 设施真的很棒。
它创建了一个增强的调试页面,除其他外,使用 Werkzeug 调试器为堆栈中的每个点创建交互式调试控制台(见屏幕截图)。它还提供了一种非常有用的便捷调试方法dump(),用于显示有关对象/框架的信息。
要安装,可以使用pip:
pip install django_extensions
pip install Werkzeug
然后将'django_extensions' 添加到settings.py 中的INSTALLED_APPS 元组并使用新扩展启动开发服务器:
./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/
【讨论】:
在 Django 旁边使用 Jinja2。
如果您发现 Django 模板语言非常受限制(像我一样!),那么您不必拘泥于它。 Django 很灵活,模板语言与系统的其余部分松散耦合,因此只需插入另一种模板语言并使用它来呈现您的 http 响应!
我使用Jinja2,它几乎就像是 django 模板语言的增强版,它使用相同的语法,并允许您在 if 语句中使用表达式!不再制作自定义 if 标记,例如 if_item_in_list!你可以简单地说%{ if item in list %},或者{% if object.field < 10 %}。
但这还不是全部;它有更多的功能来简化模板的创建,这里我就不一一列举了。
【讨论】:
在您的视图代码中添加assert False 以转储调试信息。
【讨论】:
5 / 0。为什么是五个?不知道。
这增加了上面关于Django URL names and reverse URL dispatching的回复。
URL 名称也可以在模板中有效使用。例如,对于给定的 URL 模式:
url(r'(?P<project_id>\d+)/team/$', 'project_team', name='project_team')
您可以在模板中包含以下内容:
<a href="{% url project_team project.id %}">Team</a>
【讨论】:
由于 Django “视图”只需要是返回 HttpResponse 的可调用对象,因此您可以轻松地创建基于类的视图,例如 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 href="{{MEDIA_URL}}images/frog.jpg">A frog</a>
这是非常有用的。事实上,一般情况下,对一般视图 +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}
)
【讨论】:
render 快捷方式
我没有足够的声誉来回复有问题的评论,但重要的是要注意,如果您要使用 Jinja,它不支持模板块名称中的“-”字符,而姜戈可以。这给我带来了很多问题,并浪费了时间来试图追踪它生成的非常模糊的错误消息。
【讨论】:
webdesign app 在开始设计您的网站时非常有用。导入后,您可以添加它以生成示例文本:
{% load webdesign %}
{% lorem 5 p %}
【讨论】:
django.db.models.get_model 确实允许您在不导入模型的情况下检索它。
James 展示了它的便利性:"Django tips: Write better template tags — Iteration 4 "。
【讨论】:
每个人都知道有一个可以使用“manage.py runserver”运行的开发服务器,但你知道还有一个用于提供静态文件(CSS / JS / IMG)的开发视图吗?
新手总是感到困惑,因为 Django 没有提供任何方法来提供静态文件。这是因为开发团队认为这是现实生活中的 Web 服务器的工作。
但是在开发的时候,你可能不想设置Apache + mod_wisgi,它很重。然后你可以在 urls.py 中添加以下内容:
(r'^site_media/(?P<path>.*)$', '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 %}
<img src="{% thumbnail img_src 100x100 %}"/>
这在 Django 模板标签文档中被提及,但仅参考循环。他们没有说您也可以在其他地方(任何地方?)使用它。
【讨论】:
django.views.generic.list_detail.object_list -- 它为分页提供了所有的逻辑和模板变量(其中之一是我现在写的一千次苦差事)。 Wrapping it 允许您需要的任何逻辑。这个 gem 为我节省了很多小时在“搜索结果”页面中逐个调试错误的时间,并使过程中的视图代码更清晰。
【讨论】:
PyCharm IDE 是一个很好的编码环境,尤其是调试环境,内置对 Django 的支持。
【讨论】:
使用xml_models 创建使用 XML REST API 后端(而不是 SQL 后端)的 Django 模型。这非常有用,尤其是在对第三方 API 建模时 - 您将获得与您习惯的所有相同的 QuerySet 语法。您可以从 PyPI 安装它。
来自 API 的 XML:
<profile id=4>
<email>joe@example.com</email>
<first_name>Joe</first_name>
<last_name>Example</last_name>
<date_of_birth>1975-05-15</date_of_birth>
</profile>
现在在 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'
它还可以处理关系和集合。我们每天都在大量使用的生产代码中使用它,所以即使它是测试版,它也非常有用。它还有一组很好的存根,您可以在测试中使用它们。
(免责声明:虽然我不是这个库的作者,但我现在是一名提交者,做了一些小的提交)
【讨论】:
使用数据库迁移。使用South。
【讨论】: