2011-06-20 39 views
20

Ứng dụng của tôi có người dùng tạo trang. Trong màn hình Trang của quản trị viên, tôi muốn liệt kê Người dùng đã tạo trang và trong danh sách đó, tôi muốn tên người dùng có liên kết đến trang người dùng trong quản trị viên (không phải Trang).Quản trị Django liên kết với các đối tượng liên quan

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

Tôi đã hy vọng rằng bằng cách tạo liên kết trong list_display, nó sẽ mặc định liên kết với đối tượng người dùng thực, nhưng nó vẫn đi tới Trang.

Tôi chắc chắn rằng tôi thiếu thứ gì đó đơn giản ở đây.

Trả lời

12

Thêm phần này vào mô hình của bạn:

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" 

Bạn cũng có thể cần phải thêm dòng sau vào phía trên cùng của models.py:

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

Trong admin.py, trong list_display, thêm user_link:

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

Không cần list_display_links.

+1

Cảm ơn! để làm rõ, thêm điều đó vào mô hình Trang của tôi? – Brenden

+0

Có, thêm đoạn mã đầu tiên vào mô hình Trang của bạn. – Udi

+0

Có thể thực hiện điều này trên trang thay đổi thực tế thay vì chế độ xem danh sách không? – agf

25

Sửa đổi mô hình của bạn là không cần thiết và thực tế là không đúng (thêm chế độ xem logic dành riêng cho quản trị viên vào mô hình của bạn? Yuck!) Có thể thậm chí không thể thực hiện được trong một số trường hợp.

May mắn thay, nó có thể tất cả được thực hiện từ lớp 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) 

Sửa 2016/01/17:
câu trả lời Cập nhật để sử dụng make_safe, vì allow_tags hiện đang bị phản đối.

+1

Cảm ơn bạn, câu trả lời tốt hơn nhiều so với câu trả lời khác! (có lẽ dễ hiểu, như Django đã phát triển một LOT kể từ năm 2011 ...) – janos

+3

'readonly_fields = ('user_link')' không 'read_only_fields = ('user_link')' –

+4

'obj.user.pk' tốt hơn, trong trường hợp chính khóa không được gọi là 'id'. – Dan

0

Tôi cần điều này cho rất nhiều trang quản trị của mình, vì vậy tôi đã tạo một bản mix cho nó xử lý các trường hợp sử dụng khác nhau. Bạn chỉ cần thêm:

change_links = ['field'] 

vào lớp ModelAdmin của bạn.

Xem trang GitHub để biết thêm thông tin. Hãy thử nó và cho tôi biết nó hoạt động như thế nào!

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

+0

Tôi đã thử nó và nó đã không làm việc cho tôi, nó có thể là do tài liệu hướng dẫn. – filtfilt

+0

@filtfilt bạn có thể mở một vấn đề trên trang GitHub mô tả sự cố của bạn không? – rednaw

+0

@filtfilt có thể là do thứ tự sai của thừa kế, trước tiên bạn nên đặt 'AdminChangeLinksMixin'. Đó là sai trong readme, cập nhật mà bây giờ. – rednaw

2

tôi quyết định để thực hiện một mixin quản trị đơn giản mà trông như thế này (xem docstring để sử dụng):

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

Bạn thực sự không cần' ContentType' cho việc này; bạn chỉ có thể sử dụng 'obj._meta.model' (hoặc' obj .__ class__'). – WhyNotHugo

Các vấn đề liên quan