最喜欢的Django提示和功能?


308

受问题系列“ ...的隐藏功能”的启发,我很想知道您最喜欢的Django提示或您所知的鲜为人知但有用的功能。

  • 请每个答案仅包含一个提示。
  • 添加Django版本要求(如果有)。

Answers:


221

我将从我自己的提示开始:)

在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 ” 获得了这个技巧。


75
您不应该对回答自己问题的人投反对票。即使预先确定,也鼓励这样做。
Paolo Bergantino,

19
这是一个好主意,我仍然很难理解为什么它不是默认值。有多少人在同一台计算机上测试和部署?
SingleNegationElimination

19
这可以缓解您始终输入os.path.join()的麻烦,该方法非常烦人:j = lambda filename: os.path.join(PROJECT_DIR, filename)。然后,您只需要输入j("static")
wr。

13
如果您在Windows上,请替换反斜杠:os.path.join(PROJECT_DIR,“ templates”)。replace('\\','/')
Peter Mortensen

7
如果您真的想在Django中解决此问题,请在code.djangoproject.com/ticket/694中发表评论,要求核心开发人员重新考虑该wontfix决定。
索林2010年


119

使用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(例如重定向)将使装饰器短路并按预期工作。


4
@becomingGuru-它会自动发生。
多米尼克·罗杰

15
很好,除非您返回一些HttpResponseRedirect()和一些render_to_response()。然后重定向失败。
马修·申克尔

17
我不喜欢 “显式胜于隐式”。装饰器没有告诉它确切的时间是什么时候渲染到。
陶Szelei

2
@Matthew Schinckel,它实际上不会弄乱重定向-如果您返回HttpResponse对象,它只会将其传递而不进行修改
Jiaaro

20
我认为从Django 1.3开始,这种方法现在是多余的,请参阅django.shortcuts.render()docs.djangoproject.com/en/dev/topics/http/shortcuts/#render
Dolph

101

我在网站的所有模板上使用了一组自定义标签。在寻找一种自动加载的方式(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')。


@Steef,您为我节省了很多时间/心痛/字节。
orokusaki 2010年

非常好。谢谢。另外,自定义标签存储库也非常适合共享内容,您认为吗?
Leandro Ardissone 2010年

除非其他人必须维护您的代码,否则这很好。认为:“最少魔术的原理”
里奇丰富的

96

如果您正在处理多个Django项目,则Virtualenv + Python = life saver,并且它们有可能不都依赖于同一版本的Django /应用程序。


15
这是唯一的滚动方式!
未来派

3
您能为django添加virtualenv的一些教程链接吗?
BozoJoe

2
@BozoJoe:在终端执行此操作:virtualenv myNewEnv --no-site-packages; . myNewEnv/bin/activate; pip install django; 而且就可以了!
SingleNegationElimination 2011年

87

不要对您的网址进行硬编码!

请改用网址名称,然后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标记的模板中使用该名称。


1
我同意这一点。我开始使用硬编码的url,当我更改url格式以适应某些更改时,它使我陷入了一个项目。我花时间回头研究所有内容,并替换硬编码的URL。我唯一的大抱怨是url标签错误会杀死整个页面,而硬编码只会弄乱单个链接。
ricree

21
这不应该是隐藏的功能,这是最佳实践,也是唯一的飞行方法。
Skylar Saveland

1
@skyl几乎不是“唯一的飞行方式”。我当时在Django开发冲刺中,Adrian Holovaty(Django的创建者之一)说他甚至都不使用url标签...。他的立场是网址无论如何都不应更改(如果您希望对自己的用户友好)用户)。
TM。

您也可以在模板中使用它,例如{% url path.to.view.name arg1 arg2 %} docs.djangoproject.com/en/dev/ref/templates/builtins/…– SingleNegationElimination 2010
29

如果您使用jinja2,只需添加reverse如下代码environment.filters['url'] = django.core.urlresolvers.reverse,即可在模板中使用它:({{ 'view-name'|url(arg1, arg2)|e }}“ e”是转义一些字符以包含在HTML中的必要条件)
SingleNegationElimination 2010年


79

不要编写自己的登录页面。如果您使用的是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'),
)

1
凉!我不知道我们可以重用管理员登录页面。谢谢!
Joshua Partogi,2009年

66

上下文处理器很棒。

假设您有一个不同的用户模型,并且希望将其包含在每个响应中。而不是这样做:

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)

因此,您想以某种方式通知我们已发布新帖子的众多Blog 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模型,然后在保存后执行该函数,我们就可以了。


4
如今,在比较Web框架时,Django的Signals对我来说是必不可少的功能。编写一个松散耦合的论坛,这很好,它可以侦听“签名”模块中的更新,但实际上并不需要该模块运行,也可以与实现相同功能的兼容模块一起使用。我不知道为什么信号不那么广为人知和流行。
李B

如果我们在项目中使用一些可重用的应用程序,那么信号通常对于避免紧密耦合和代码混乱非常重要。您提供了django应用程序松散耦合的绝佳示例,为此+1。
Lukasz Korzybski 2010年

你知道信号是否异步吗?
凯达雷

“假设您有一个不同的用户模型,并且希望在每个响应中都包含该模型。” -将用户加入会话。这样可以为每个请求节省数据库命中率。
jammon 2011年

信号的呼叫是同步的。我认为,某种异步作业机制更适合在Twitter / Facebook / etc(例如,rabbitmq)上发布,因此不在网站上的用户不会按需挂起。
gorsky 2011年

58

当我刚开始的时候,我不知道有一个分页器,请确保您知道它的存在!


2
:D对我来说一样!我花了几天的时间分页!
vikingosegundo

46

使用IPython可以进入任何级别的代码,并使用IPython的功能进行调试。一旦安装了IPython,就可以将此代码放到要调试的位置:

from IPython.Shell import IPShellEmbed; IPShellEmbed()()

然后,刷新页面,转到runserver窗口,您将进入交互式IPython窗口。

我在TextMate中设置了一个代码段,所以我只需键入ipshell并单击Tab。没有它,我活不下去。


22
更好的安装ipdb,然后键入ipdb.set_trace()
TomaszZieliński2010年

或使用Eclipse / PyDev的调试器。:-)
jMyles

3
导入ipdb; ipdb.set_trace()FTW!
哈瑟克

43

运行开发SMTP服务器,该服务器将仅输出发送给它的任何内容(如果您不想在开发服务器上实际安装SMTP)。

命令行:

python -m smtpd -n -c DebuggingServer localhost:1025

12
您可以出于相同目的在django 1.2中使用控制台和文件电子邮件后端
Dmitry Shevchenko 2010年

优秀!完美的注册!+1
BozoJoe

3
在Django 1.2中的替代设置:EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' ..将把电子邮件打印到manage.py输出。
vdboor 2011年

41

django-admin文档中

如果使用Bash shell,请考虑安装Django bash完成脚本,该脚本extras/django_bash_completion位于Django发行版中。它启用django-admin.pymanage.py命令的制表符补全,因此您可以例如...

  • 类型 django-admin.py
  • 按[TAB]查看所有可用选项。
  • 键入sql,然后按[TAB],以查看名称以开头的所有可用选项sql

1
这比我预期的有用。谢谢!
Jeeyoung Kim

默认情况下,至少在较新的Ubuntu中是这样。:-)当它第一次冒出来时,我感到很惊讶。
奥迪尼奥-费尔蒙特

40

./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

这将改变您的调试方式。


37

我喜欢使用Python调试器pdb调试Django项目。

这是学习使用方法的有用链接:http : //www.ferg.org/papers/debugging_in_python.html


13
这是天赐的礼物。要提供更多信息,只需在代码的任何行上添加以下内容:“ import pdb; pdb.set_trace()”。刷新页面。它会挂起。现在转到运行开发服务器的终端窗口。现在它应该是一个交互式外壳程序,您可以在其中访问粘贴了调试代码的代码中的所有变量。
priestc


36

使用Jinja2与Django一起。

如果您发现Django模板语言非常严格(像我一样!),那么您不必受其限制。Django非常灵活,并且模板语言与系统的其余部分松散耦合,因此只需插入另一种模板语言并使用它来呈现您的http响应!

我使用Jinja2,它几乎像django模板语言的功能强大的版本,它使用相同的语法,并允许您在if语句中使用表达式!不再制作自定义的if标签,例如if_item_in_list!你可以简单地说%{ if item in list %},或{% if object.field < 10 %}

但这还不是全部;它具有更多的功能来简化模板的创建,尽管这里没有全部介绍。


我也使用并喜欢Jinja2,但是我发现与“ contrib”应用程序有些耦合。特别是,管理工具与Django模板紧密相关。另外,我必须在contrib.auth中重新创建登录装饰器,以使其对Jinja2友好,但又不太难。
Joe Holloway

24
不要用jinja2替换模板系统,只需“添加”它,不要删除Django模板。将Jinja2用于您自己的视图,并让管理界面继续使用django模板语言。
hasen 2009年

4
我非常同意这一点。Django的有限语法在大多数情况下是可以容忍的,但是当您达到制作自定义标签并弄清实际上有多难的程度时,Jinja2令人耳目一新
SingleNegationElimination

另外,如果您想对模板源进行任何元编程,Jinja2会更加令人愉悦,因为您可以直接访问已解析模板的AST。遍历AST使任务变得很简单,例如找出哪些模板扩展了基本模板,或在模板源代码块中列出了未绑定的变量。
编码器

5
值得庆幸的是,在Django 1.2中,IF标签更加智能
Nixarn 2010年

35

assert False在您的视图代码中添加转储调试信息。


4
我认为断言False更直观= D
Jiaaro

13
如果您正在django开发服务器中运行项目,请使用python的pdb模块。这是一种更强大的调试方式:import pdb; pdb.stack_trace()
mazelife

pdb非常有用,除非您非常快地进行调试,否则您可能会使连接超时。
Stephen Paulger

4
我总是用5 / 0自己。为什么是五个?不知道。
JasonSmith,2009年

@StephenPaulger真的吗?我的浏览器(firefox / w firebug)在调试时似乎满足等待几分钟的响应。
TM。

34

这增加了上面关于Django URL名称和反向URL调度的答复

URL名称也可以在模板中有效使用。例如,对于给定的URL模式:

url(r'(?P<project_id>\d+)/team/$', 'project_team', name='project_team')

您可以在模板中包含以下内容:

<a href="{% url project_team project.id %}">Team</a>

27

由于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),
)

2
FWIW,django作者实际上在几个地方使用了基于类的视图,例如contrib.formtools:code.djangoproject.com/browser/django/trunk/django/contrib/…–
mazelife

3
如果添加调用方法,则可以创建一个名为RestfulResource的类,然后使urls.py指向实例。
Stephen Paulger 09年

1
新的(Django 1.3?)通用视图是基于类的。
gorsky 2011年

21

而不是使用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}
    )

通过使用django-annoying中可用的@render_to装饰器,保存更多LOC。bitbucket.org/offline/django-annoying
令人讨厌的2010年

6
..或者使用新的render1.3(从Django的快捷方法docs.djangoproject.com/en/dev/topics/http/shortcuts/#render
gorsky

20

我没有足够的声誉来回答有问题的评论,但是请务必注意,如果您要使用Jinja,则它不支持模板块名称中的'-'字符,而Django则支持。这给我带来了很多问题,并浪费了很多时间来跟踪它生成的非常模糊的错误消息。


一项注释可能适用于或可能不适用于“来自jinja的错误消息”。确保在settings.py中设置TEMPLATE_DEBUG = False。由于某些原因,这会给您Jinja模板带来的有意义的错误。
卡尔·G

19

开始设计您的网站时,webdesign应用程序非常有用。导入后,您可以添加以下内容以生成示例文本:

{% load webdesign %}
{% lorem 5 p %}

4
仅供参考,对于使用Jinja2而不是Django模板的任何人,您都可以这样做:{{lipsum(5)}}
Joe Holloway,2009年


19

每个人都知道有一个可以使用“ 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/上提供。

当然,不要在生产环境中使用它。


6
我在开发人员模式下使用了此命令,只是为了确保我不会忘记在生产环境中将其关闭,我将该URL规则包装在仅DEBUG作为条件文件中。
sghael

18

我是从soul-thumbnails的文档中学到的应用程序。您可以在模板标签中使用“ as”关键字,以在模板中的其他位置使用调用结果。

例如:

{% url image-processor uid as img_src %}
<img src="{% thumbnail img_src 100x100 %}"/>

在传递Django templatetag文档时提到了这一点,但仅引用了循环。他们并没有要求您也可以在其他任何地方使用此功能。


7
关键字“ as”是否可以与模板标签一起使用取决于此特定标签。它不是由Django本身定义的,而是由单个标签定义的,具体取决于它们的含义。看看上面提到的url标签,看看如何使用“ as”:code.djangoproject.com/browser/django/trunk/django/template/…–
vikingosegundo

16

django.views.generic.list_detail.object_list-它提供了用于分页的所有逻辑和模板变量(我已经写了数千次的苦工之一)。 包装它允许您需要任何逻辑。这个gem为我节省了很多时间在“搜索结果”页面中调试一次错误的调试,并在此过程中使视图代码更加整洁。


1
您可以在djangobook.com/en/2.0/chapter11找到有关通用视图的新章节。发表评论的人转到该书的Django 1.0之前版本(Django图书1.0)
EstebanKüber,09年


14

使用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'

它还可以处理关系和集合。我们每天都在大量使用的生产代码中使用它,因此即使它是beta版,它也非常有用。它还具有一组可以在测试中使用的存根。

(免责声明:虽然我不是该库的作者,但我现在是一名提交者,做了一些次要的提交)


有趣的项目,继续努力!
谢尔盖·戈洛夫琴科

谢谢,这很方便:-)
godswearhats

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.