2011-06-20 123 views
20

我的應用程序有創建頁面的用戶。在管理員的頁面屏幕中,我想列出創建該頁面的用戶,並在該列表中,我希望用戶名可以鏈接到管理員(而不是頁面)的用戶頁面。Django管理鏈接到相關對象

class PageAdmin(admin.ModelAdmin): 
    list_display = ('name', 'user',) 
    list_display_links = ('name','user',) 
admin.site.register(Page, PageAdmin) 

我希望通過使其在list_display一個鏈接它會默認鏈接到實際的用戶對象,但它還是到頁。

我確定我在這裏錯過了一些簡單的東西。

回答

12

添加到您的模型:

def user_link(self): 
     return '<a href="%s">%s</a>' % (reverse("admin:auth_user_change", args=(self.user.id,)) , escape(self.user)) 

    user_link.allow_tags = True 
    user_link.short_description = "User" 

您可能還需要將以下添加到models.py頂部:

from django.template.defaultfilters import escape 
    from django.core.urlresolvers import reverse 

admin.py,在list_display,加user_link

list_display = ('name', 'user_link',) 

不需要list_display_links

+1

謝謝!澄清,添加到我的Page模型? – Brenden

+0

是的,將第一個代碼片段添加到您的Page模型中。 – Udi

+0

是否可以在實際更改頁面而不是列表視圖上執行此操作? – agf

25

修改你的模型是沒有必要的,它實際上是一個不好的做法(在你的模型中添加特定於管理員的視圖邏輯?Yuck!)在某些情況下甚至不可能。

幸運的是,它都可以從的ModelAdmin類實現:

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


class PageAdmin(admin.ModelAdmin): 
    # Add it to the list view: 
    list_display = ('name', 'user_link',) 
    # Add it to the details view: 
    read_only_fields = ('user_link',) 

    def user_link(self, obj): 
     return mark_safe('<a href="{}">{}</a>'.format(
      reverse("admin:auth_user_change", args=(obj.user.pk,)), 
      obj.user.email 
     )) 
    user_link.short_description = 'user' 


admin.site.register(Page, PageAdmin) 

編輯2016年1月17日
更新答案使用make_safe,因爲allow_tags現在已經過時。

+1

謝謝,比另一個更好的答案! (可能是可以理解的,因爲Django自2011年以來已經發展了很多...) – janos

+3

'readonly_fields =('user_link')'not'read_only_fields =('user_link')' –

+4

更好的'obj.user.pk',鍵不叫'id'。 – Dan

0

我需要這很多我的管理頁面,所以我創建了一個mixin處理不同的用例。您只需添加:

change_links = ['field'] 

到您的ModelAdmin類。

有關更多信息,請參閱GitHub頁面。試試吧,讓我知道它是如何運作的!

https://github.com/gitaarik/django-admin-relation-links

+0

我試過了,它不適合我,可能是因爲文檔。 – filtfilt

+0

@filtfilt您可以在GitHub頁面上打開描述您的問題的問題嗎? – rednaw

+0

@filtfilt可能是因爲繼承的順序錯誤,你應該首先將'AdminChangeLinksMixin'放入。自述文件中有錯,現在更新。 – rednaw

2

我決定做一個簡單的管理混入看起來像這樣(見文檔字符串的使用):

from django.contrib.contenttypes.models import ContentType 
from django.utils.html import format_html 
from rest_framework.reverse import reverse 


class RelatedObjectLinkMixin(object): 
    """  
    Generate links to related links. Add this mixin to a Django admin model. Add a 'link_fields' attribute to the admin 
    containing a list of related model fields and then add the attribute name with a '_link' suffix to the 
    list_display attribute. For Example a Student model with a 'teacher' attribute would have an Admin class like this: 

    class StudentAdmin(RelatedObjectLinkMixin, ...): 
     link_fields = ['teacher'] 

     list_display = [ 
      ... 
      'teacher_link' 
      ... 
     ] 
    """ 

    link_fields = [] 

    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     if self.link_fields: 
      for field_name in self.link_fields: 
       func_name = field_name + '_link' 
       setattr(self, func_name, self._generate_link_func(field_name)) 

    def _generate_link_func(self, field_name): 
     def _func(obj, *args, **kwargs): 
      related_obj = getattr(obj, field_name) 
      if related_obj: 
       content_type = ContentType.objects.get_for_model(related_obj.__class__) 
       url_name = 'admin:%s_%s_change' % (content_type.app_label, content_type.model) 
       url = reverse(url_name, args=[related_obj.pk]) 
       return format_html('<a href="{}" class="changelink">{}</a>', url, str(related_obj)) 
      else: 
       return None 
     return _func 
+0

你真的不需要'ContentType';你可以使用'obj._meta.model'(或'obj .__ class__')。 – WhyNotHugo