Django Admin ссылки на связанные объекты - PullRequest
26 голосов
/ 21 июня 2011

В моем приложении есть пользователи, которые создают страницы.На странице администратора страницы я хотел бы перечислить пользователя, который создал страницу, и в этом списке я хотел бы, чтобы имя пользователя имело ссылку, которая ведет на страницу пользователя в admin (а ​​не на страницу).

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

Я надеялся, что, сделав его ссылкой в ​​list_display, он по умолчанию будет ссылаться на фактический пользовательский объект, но он все равно перейдет на страницу.

Я уверен, что яЯ упускаю что-то простое здесь.

Ответы [ 5 ]

34 голосов
/ 26 августа 2015

Изменение вашей модели не требуется, и на самом деле это плохая практика (добавление логики представления, специфичной для администратора, в ваши модели? Блин!) В некоторых сценариях это может быть даже невозможно.

К счастью, все это может быть достигнуто с помощью класса ModelAdmin:

from django.urls 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-01-17: Обновлен ответ для использования make_safe, поскольку allow_tags устарело.

Изменить 2019-06-14: Обновленный ответ для использования django.urls, поскольку начиная с Django 1.10 django.core.urls устарел.

16 голосов
/ 21 июня 2011

Добавьте это к вашей модели:

  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.urls import reverse

В admin.py, в list_display, добавьте user_link:

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

Нет необходимости в list_display_links.

4 голосов
/ 02 октября 2017

Я решил создать простой админский миксин, который выглядит следующим образом (см. Документацию для использования):

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
3 голосов
/ 06 апреля 2018

Вам необходимо использовать format_html для современных версий od django

@admin.register(models.Foo)
class FooAdmin(admin.ModelAdmin):
    list_display = ('ts', 'bar_link',)

    def bar_link(self, item):
        from django.shortcuts import resolve_url
        from django.contrib.admin.templatetags.admin_urls import admin_urlname
        url = resolve_url(admin_urlname(models.Bar._meta, 'change'), item.bar.id)
        return format_html('<a href="{url}">{name}</a>'.format(url=url, name=str(item.bar)))
2 голосов
/ 31 марта 2017

Мне нужно было это для многих моих страниц администратора, поэтому я создал для него миксин, который обрабатывает разные варианты использования.Вы просто добавляете:

change_links = ['field']

к вашему ModelAdmin классу.

См. Страницу GitHub для получения дополнительной информации.Попробуйте и дайте мне знать, как это работает!

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

...