Django内联链接编辑模型

7 投票
2 回答
6638 浏览
提问于 2025-04-18 15:55

我知道这个问题已经被问过很多次了,但随着Django版本的更新,我想再问一次:

我正在使用Django自带的用户模型User(不是我自己在models.py里定义的),并且创建了一个新的模型,这个模型通过外键关联到User。

models.py

class Plan(models.Model):
    user = models.ForeignKey(User)

我可以在admin.py里简单地显示每个用户的Plan,方法如下:

class PlanInline(admin.TabularInline):
    model = Plan
    extra = 0

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    inlines = [PlanInline,]

admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)

但事情变得有点复杂了。我想添加一个模型,这个模型的外键指向Plan

class Order(models.Model):
    plan = models.ForeignKey('Plan')

我希望能看到每个Plan的所有Orders。目前,在Django Admin中,无法实现嵌套的内联显示(除非修改HTML,但我不想这样做):

User 
     -> Plan 1 
              -> Order 1
              -> Order 2

     -> Plan 2
              -> Order 3

所以我的想法是在User Admin中只显示每个计划的一个链接,指向编辑Plans的页面,并将Orders作为内联显示:

class OrderInline(admin.TabularInline):
    model = Order
    extra = 0

class PlanAdmin(admin.ModelAdmin):
    inlines = [OrderInline,]

admin.site.register(Plan, PlanAdmin)

我的问题是,如何在用户管理界面中显示指向Plan的链接呢?

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    ??? LINK ????

我看到了一些关于这个话题的解决方案:Django InlineModelAdmin: Show partially an inline model and link to the complete model,但是这些方案有点“麻烦”,因为它们要求我们在代码中写HTML和绝对路径。

然后我在Django项目上看到这个问题单:https://code.djangoproject.com/ticket/13163。这似乎正是我想要的,而且这个问题单已经“修复”了。所以我尝试像修复中那样添加show_change_link = True

class PlanInline(admin.TabularInline):
    model = Plan
    extra = 0
    show_change_link = True

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    show_change_link = True
    inlines = [UserProfileInline, PlanInline]

但这并没有奏效(而且我没有任何日志或错误信息)。

有没有什么办法可以以一种干净的方式做到这一点呢?

2 个回答

11

关于django 1.8的更新

show_change_link = True

https://github.com/django/django/pull/2957/files

6

我建议你添加一个自定义的 PlanInline 方法,让它返回一个链接,看看这样是否有帮助。大致可以这样做:

from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse

class PlanInline(TabularInline):
   model = Plan
   readonly_fields = ('change_link',)
   ...other options here...

   def change_link(self, obj):
      return mark_safe('<a href="%s">Full edit</a>' % \
                        reverse('admin:myapp_plan_change',
                        args=(obj.id,)))

其实我们在这里做的就是创建一个自定义方法,这个方法返回一个指向修改页面的链接(这个具体的实现没有经过测试,如果有解析错误请见谅,但你应该能明白我的意思),然后把它添加到只读字段中,具体可以参考这里的说明:https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

关于 change_link 方法,有几点需要注意:你需要把视图名称中的 'myapp' 替换成你实际的应用名称。mark_safe 方法的作用是告诉模板引擎,这段文本是安全的,可以直接渲染成 HTML。

撰写回答