Django Admin, связанный с связанными объектами
В моем приложении есть пользователи, которые создают страницы. На экране страницы администратора я хотел бы указать Пользователя, который создал страницу, и в этом списке я хотел бы, чтобы имя пользователя имело ссылку, которая идет на страницу пользователя в admin (а не на странице).
class PageAdmin(admin.ModelAdmin):
list_display = ('name', 'user', )
list_display_links = ('name','user',)
admin.site.register(Page, PageAdmin)
Я надеялся, что, создав ссылку в списке list_display, по умолчанию будет ссылаться на фактический объект пользователя, но он все равно переходит на страницу.
Я уверен, что мне не хватает чего-то простого здесь.
Ответы
Ответ 1
Добавьте это к вашей модели:
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
.
Ответ 2
Модификация вашей модели не обязательна, и на самом деле это плохая практика (добавление логики представления, специфичной для администратора, в ваши модели? Блин!) Это может быть невозможно даже в некоторых сценариях.
К счастью, все это может быть достигнуто с помощью класса 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
устарел.
Ответ 3
Я решил создать простой админ-микрин, который выглядит так (см. docstring для использования):
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
Ответ 4
Вам нужно использовать 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)))
Ответ 5
Мне нужно было это для многих моих страниц администрирования, поэтому я создал для него mixin, который обрабатывает различные варианты использования. Вы просто добавляете:
change_links = ['field']
в ваш класс ModelAdmin
.
Дополнительную информацию см. на странице GitHub. Попробуйте и дайте мне знать, как это работает!
https://github.com/gitaarik/django-admin-relation-links