你应该使用 Django admin 的 9 个理由 已翻译 100%

有来有趣 投递于 2015/12/09 21:11 (共 6 段, 翻译完成于 12-16)
阅读 10787
收藏 95
5
加载中

本文源自 Reddit 上对我最近的一个帖子的评论:

“问题是,我问到的每个人都持反对意见,他们认为 admin 只限于超级用户,很不灵活并且是难以定制。”

        —来自 Reddit 的 andybak

我现在要澄清这个误解。Django 的 admin 绝对是软件中的亮点,可以有效的加速你的开发。

这里有一些我能想到的很有用的 Django 的 admin 模块的窍门。

(对于 Django admin 不太熟悉的人,先简单解释几个名词)

Changeform 是可以编辑对象的页面。

Changelist 页面可以列出指定类型的对象。你可以指定过滤对象的条件及对对象的操作。点击 changelist 里的对象一般会跳转到对象的 changeform 页面。

为了让这些敲门更具可操作性,我们使用了与真实问题几乎一致的场景。假设我们有一个简单的网站,访客可以上传可爱的动物图片并进行评论。这是不是很流行呢?

zicode
zicode
翻译于 2015/12/10 15:23
1

Tip 1:Django admin 后台不限于用 Django 开发的网站

虽然 Django admin 管理界面可以非常友好的用在 Django 项目的其它部分,它同样可以很容易用于其它像传统的数据库或具有一个可怕的的管理界面的网站。而且这也是评估 Django 是否会满足您的需求的最佳途径。

你需要做的仅是:

  1. 在你的 Django 项目中建立一个新的应用,并确保你已经连接好传统数据库 ,通过 settings.py 文件中的 DATABASES 的设置。

  2. 将你的数据表定义为 Django 的模型。正如它的名字所表述的,manage.py inspectdb 是一个非常有用的命令:检测现有的数据库,并打印出自动生成的 Django 模型。

  3. 创建 admin.py 文件,并放在那里,唉,管理相关的。稍后将详细说明这个。

说到我们的动物“的网站,是由进屎的脑袋写出来的,所以管理界面看起来像......你知道的,不是很好。为了解决这个问题,我们通过几个 Django 模型重构了数据库结构,实现一个简单的管理界面:

# models.py
class Picture(models.Model):
    DOG = 1
    CAT = 2
    ANIMAL_KIND_CHOICES = (
        (DOG, 'dog'),
        (CAT, 'cat'),
    )

    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, related_name='pictures')
    animal_kind = models.IntegerField(choices=ANIMAL_KIND_CHOICES)
    photo = models.ImageField(upload_to='animals')
    is_promoted = models.BooleanField(default=False)


class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()


class Comment(models.Model):
    author = models.ForeignKey(Author, related_name='comments')
    picture = models.ForeignKey(Picture, related_name='comments')
    comment = models.TextField()
    editors_note = models.TextField()

# admin.py
class PictureAdmin(admin.ModelAdmin):
    list_display_fields = ('photo', 'animal_kind', 'author', 'is_promoted', )


class AuthorAdmin(admin.ModelAdmin):
    list_display_fields = ('name', 'email', )


class CommentAdmin(admin.ModelAdmin):
    list_display_fields = ('picture', 'author', )
张春晖
张春晖
翻译于 2015/12/11 11:59
1

Tip #2: 按你喜欢的方式筛选你的数据

很多人使用 Django admin 后台对指定字段进行筛选。要知道,把一个字段名放到 list_filter 列表里就可以了。同时它也非常容易地创建一个自定义过滤器!

假如最终你决定要推广所有有 100+ 的帖子的作者。但是,我们如何区分它们?让我们创建一个过滤器,并把它添加到我们的变更列表。

class ProductiveAuthorsFilter(admin.SimpleListFilter):
    parameter_name = 'is_productive'
    title = 'Productive author'
    YES, NO = 1, 0

    # Number of comments for an author to be considered a productive one
    THRESHOLD = 100

    def lookups(self, request, model_admin):
        return (
            (self.YES, 'yes'),
            (self.NO, 'no'),
        )

    def queryset(self, request, queryset):
        qs = queryset.annotate(Count('comments'))

        # Note the syntax. This way we avoid touching the queryset if our
        # filter is not used at all.
        if self.value() == self.YES:
            return qs.filter(comments__count__gte=self.THRESHOLD)
        if self.value() == self.NO:
            return qs.filter(comments__count__lt=self.THRESHOLD)

        return queryset


class PictureAdmin(admin.ModelAdmin):
    list_filters = [..., ProductiveAuthorsFilter]

现在,我们可以很容易地选出我们的核心作者。那么我们如何开始向他们推广呢?让我们进入下一部分。

Tip #3:添加动作(操作函数)到 'actions'

这可是内容管理者的天赐之物。还记得在每个模型的列表顶部的“动作”工具栏不?我们是不是非常方便的先选择一些图片,然后只需单击一下就“推广”给作者了?现在让我们来实现它:

class PictureAdmin(admin.ModelAdmin):
    actions = ['promote', ]

    def promote(self, request, queryset):
        queryset.update(is_promoted=True)
        self.message_user(request, 'The posts are promoted')
    promote.short_description = 'Promote the pictures'

就是这样!不用再一个挨一个的打开每个表单!另外,它很容易进一步增加我们的动作,例如,添加一个过渡表单。关于这点,Django 文档 有段非常棒的讲解


张春晖
张春晖
翻译于 2015/12/11 12:09
1

Tip #4: 搜索你需要的所有字段

好吧,过滤器是很酷,但让我们关注了一下就搜索工具。在几乎所有的安装我见过的搜索框是用来在一个模型中的字段搜索。但是,当你意识到它可以处理关系的 Django 搜索真正的亮点。因此,假设我们希望它在图片“的标题,作者姓名和注释”文本进行搜索。我们如何做到这一点?

class PictureAdmin(admin.ModelAdmin):
    search_fields = ('title', 'author__name', 'comments__text', )

如果你的数据库是够大,不要忘记添加一些全文索引来增加搜索速度。

Tip #5: "在站点查看"的简单实现

在站点查看一个对象的界面是非常普及的需求,默认情况下,你必须打开该对象的表单,然后点击按钮“在站点查看”。以下代码展示如何使此过程更容易一些:

class PictureAdmin(admin.ModelAdmin):
    list_fields = [..., 'object_link']

    def object_link(self, item):
        url = item.get_absolute_url()
        return u'<a href={url}>open</a>'.format(url=url)
    object_link.short_description = 'View on site'
    object_link.allow_tags = True

这段代码给列表中每个对象都添加了“在站点查看”的链接。在此,我们假定你的模型(Model)已经实现了get_absolute_url()方法。如果还没有 - 那现在就去实现 ,这将为你节省很多时间。你也可能会想将这个片段转移到一个 mixin,或公用的 admin 基类。

张春晖
张春晖
翻译于 2015/12/14 13:00
1

Tip #6: 在列表页就地编辑字段

假设我们需要给评论加一个编辑的备注。很自然,我们希望不需要对每条评论都去打开评论的changeform。要做到这点,我们可以稍微修改一下ModelAdmin:

class CommentAdmin(admin.ModelAdmin):
    list_display_fields = ('picture', 'author', 'editors_note', )
    list_editable = ('editors_note', )

这样就搞定了,现在打开评论列表,可以按照需要进行过滤,还可以在评论上即时添加备注。

Tip #7: 根据需要自定义 total 字段

每个 changelist 最下方都有一行列出总数(total)。假设我们需要把猫和狗的图片数量区分开来。这个功能需要的代码稍微多一些:我们需要重载 changelist 和 html 模板(更多内容参考模板重载)。

from django.contrib.admin.views.main import ChangeList

class PicturesChangeList(admin.ChangeList):
    def get_results(self, request):
        super(PicturesChangeList, self).get_results(request)
        totals = self.result_list.aggregate(
            dogs_count=Sum(Case(When(animal_kind=Picture.DOG, then=1),
                           output_field=IntegerField())),
            cats_count=Sum(Case(When(animal_kind=Picture.CAT, then=1),
                           output_field=IntegerField())))
        self.totals = totals


class PictureAdmin(admin.ModelAdmin):
    def get_changelist(self, request):
        return PicturesChangeList

模板的内容:

{% extends 'admin/change_list.html' %}
{% block result_list %}
    {{ block.super }}
    <p>
        There are
        <strong>
            {{ cl.totals.dogs_count|default:'none' }} dogs and
            {{ cl.totals.cats_count|default:'none' }} cats
        </strong>
        on this page.
    </p>
{% endblock %}

Tip #8: 对某些用户只读的 admin 界面

啥意思?假设你的祖母打算瞅一眼这些可爱的图片,她站在你背后,觉得 Django 的 admin 界面挺有意思。不过你能肯定,她要是使用 admin 界面,恐怕一个按钮的点击就能毁掉整个网站。那么,我们加上 grandma-proof™,这样就支持只读的 admin 界面(就是某人说的“数据浏览”):

class GrandmaProofAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.username == 'granny':
            return [f.name for f in self.model._meta.fields]
        else:
            return super(GrandmaProofAdmin, self).get_readonly_fields(request, obj)


class PictureAdmin(GrandmaProofAdmin):
    ...

现在你可以安全的把修改图片的权限放开给你的祖母,这样她就能浏览图片列表。要注意这个方案肯定不能适用于所有使用场景,你还需要处理更多的情况

zicode
zicode
翻译于 2015/12/15 13:42
1

Tip #9: 为每个对象自定义 action

有时候你需要在单个对象上执行特定的 action。‘actions’工具当然可以完成这个任务,不过过程会显得很麻烦:点击对象、选择 action、再点击一个按钮......肯定有更便捷的方式,对吧?让我们想办法只点击一次就全部搞定。

这次我们要实现老祖母的另一个宏达的想法。她希望能给某些编辑发 email,告诉他们她喜欢的所有图片。

class PictureAdmin(admin.ModelAdmin):
    list_fields = (..., 'mail_link', )

    def mail_link(self, obj):
        dest = reverse('admin:myapp_pictures_mail_author',
                       kwargs={'pk': obj.pk})
        return '<a href="{url}">{title}</a>'.format(url=dest, title='send mail')
    mail_link.short_description = 'Show some love'
    mail_link.allow_tags = True

    def get_urls(self):
        urls = [
            url('^(?P<pk>\d+)/sendaletter/?$',
                self.admin_site.admin_view(self.mail_view),
                name='myapp_pictures_mail_author'),
        ]
        return urls + super(PictureAdmin, self).get_urls()

    def mail_view(self, request, *args, **kwargs):
        obj = get_object_or_404(Picture, pk=kwargs['pk'])
        send_mail('Feel the granny\'s love', 'Hey, she loves your pet!',
                  'granny@yoursite.com', [obj.author.email])
        self.message_user(request, 'The letter is on its way')
        return redirect(reverse('admin:myapp_picture_changelist'))

但愿她现在能够满意。现在每个对象字段加上了一个链接,让她点一下就可以发送邮件。

Bonus Tip: 只需为 admin 添加一行代码来减少查询量

Django admin (Django 也是如此) 最常用也是最有用的技巧是 select_related。呃,你已经都知道了?不就是把对象的名字传给 ModelAdmin 的 list_select_related 属性来实现相关对象的预加载嘛。但是,你知道你并没有描述全部的相关对象吗?只需要设置成 True,Django 就可以自动预加载外部对象:

class PictureAdmin(admin.ModelAdmin):
    list_select_related = True

本文到此就差不多结束了,希望你能觉得有意思。别忘了在评论里分享你的看法,告诉我们对你有帮助的技巧。

zicode
zicode
翻译于 2015/12/16 10:46
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(24)

leeyi
leeyi

引用来自“ntsai”的评论

我还是喜欢xadmin。 自带admin太水
xadmin 貌似不支持Python3?
阕声云舵
阕声云舵

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。

引用来自“阕声云舵”的评论

的确井底之蛙才会这样说。看这文竟然看出来讲的是crud。。。

引用来自“杨金焕”的评论

小伙,它这个文章,不是在叙述django admin的数据crud吗?还得瑟地说一些model的如何如何配置就可以实现数据的读写表单,无聊得很,没有什么好吹的。
得 。按你逻辑只要跟models扯上关系就都是crud 了。那建议你用php的角度写篇同样内容的文章。在那边文章下面好好嘲讽一下这文章。
qycms_cn
qycms_cn

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。

引用来自“阕声云舵”的评论

的确井底之蛙才会这样说。看这文竟然看出来讲的是crud。。。
小伙,它这个文章,不是在叙述django admin的数据crud吗?还得瑟地说一些model的如何如何配置就可以实现数据的读写表单,无聊得很,没有什么好吹的。
阕声云舵
阕声云舵

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。
的确井底之蛙才会这样说。看这文竟然看出来讲的是crud。。。
crossmix
crossmix
ntsai
ntsai

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。

引用来自“雪梨苹果”的评论

果然php素质低的人多...这文章整篇没说php任何不好,也不关php任何事,这样子就烦躁了?那就说php是宇宙第一,那样满足了吧。

引用来自“杨金焕”的评论

不好意思,本人一真用dj开发一些后台应用,如机子管理监控的产品吧,对于django真的不苟同。
那只能说你DJ ADMIN 用不好。只是用到CURD而已。DJ ADMIN不好的地方就是 AUTH 太水而已。
qycms_cn
qycms_cn

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。

引用来自“雪梨苹果”的评论

果然php素质低的人多...这文章整篇没说php任何不好,也不关php任何事,这样子就烦躁了?那就说php是宇宙第一,那样满足了吧。
不好意思,本人一真用dj开发一些后台应用,如机子管理监控的产品吧,对于django真的不苟同。
qycms_cn
qycms_cn

引用来自“杨金焕”的评论

单单就一个crud就这么叼?真的以为python 这样的crud好难实现?井底之蛙,php大把框架,一键生成,有没有?如yii 的gii, 一个生成,通通都有了,controller,view,model。。

引用来自“沃尔德”的评论

django admin 不单单是 CURD,况且你要评论某东西的时候,你得对这东西先有一定的了解和使用时间才有资格 评论。啥不懂别瞎说哈。PHPER
不好意思,我一直用django开发一些东西,除了它的视图,对于它的设计思想真的不敢苟同。如果不是系统生态对它的支持与依赖,我真的不想用它。django的admin除了curd,还有auth的管理,其实真的没有什么了不起,如果对比其它的语言的产品,用起来真的不算太方便。
fys
fys
“敲门”是什么?
扁豆焖面先生
扁豆焖面先生
”我觉得p。h。p是最好的语言!没有之一!“
返回顶部
顶部