在管理渲染中将 Django 只读外键字段设置为链接

发布于 2024-10-24 04:40:59 字数 505 浏览 1 评论 0原文

我在 Django 的管理中公开了一个模型,它使用 ModelAdmin 的 readonly_fields 列表来显示“用户”字段,该字段是链接到 Django 的用户模型的 ForiegnKey。默认情况下,readonly_fields 会导致此字段呈现为包含用户电子邮件的简单文本(例如 [电子邮件受保护])。我如何更改它以呈现为该用户关联管理页面的链接? (例如 [电子邮件受保护])

I have a model exposed in Django's admin, which uses ModelAdmin's readonly_fields list to show a "user" field, which is a ForiegnKey linking to Django's User model. By default, readonly_fields causes this field to be rendered as simple text containing the user's email (e.g. [email protected]). How would I change this to render as a link to the associated admin page for that user? (e.g. <a href="/admin/auth/user/123/">[email protected]</a>)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

成熟的代价 2024-10-31 04:40:59

深入研究源代码,我发现您基本上可以将自己的字段定义为 ModelAdmin 子类中的方法,并且只需从该方法返回链接 html 即可将该字段呈现为链接。

例如

from django.contrib import admin
from django.utils.safestring import mark_safe
from django.core import urlresolvers

class MyModelAdmin(admin.ModelAdmin):

    readonly_fields = ['user_link']

    def user_link(self, obj):
        change_url = urlresolvers.reverse('admin:auth_user_change', args=(obj.user.id,))
        return mark_safe('<a href="%s">%s</a>' % (change_url, obj.user.email))
    user_link.short_description = 'User'

Digging into the source code, I found you can essentially define your own fields as methods within your ModelAdmin subclass, and you can get the field to render as a link by simply returning the link html from the method.

e.g.

from django.contrib import admin
from django.utils.safestring import mark_safe
from django.core import urlresolvers

class MyModelAdmin(admin.ModelAdmin):

    readonly_fields = ['user_link']

    def user_link(self, obj):
        change_url = urlresolvers.reverse('admin:auth_user_change', args=(obj.user.id,))
        return mark_safe('<a href="%s">%s</a>' % (change_url, obj.user.email))
    user_link.short_description = 'User'
坏尐絯℡ 2024-10-31 04:40:59

Cerin 的答案在我的 Django 1.8 项目中不起作用,因为 readonly_fields 不应包含字符串“user_link”,而应包含对已定义函数的引用:

class ProfileAdmin(admin.ModelAdmin):
    # https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
    def user(obj):
        change_url = reverse('admin:auth_user_change', args=(obj.user.id,))
        return mark_safe('<a href="{0}">{1}</a>'.format(change_url, obj.user.email))
    user.short_description = 'Edit linked user'
    raw_id_fields = ('user',)
    list_display = (user, 'last_name', 'first_name', 'specialization',)
    list_display_links = ('first_name', 'last_name', ,)
    readonly_fields = (user, 'user',)

请注意,user(obj) 会覆盖 Profile.user 字段的单个模型编辑和模型列表显示。另请注意,readonly_fields 同时使用用户和“用户”,一个呈现链接的电子邮件,另一个呈现用户名。

Cerin's answer does not work in my Django 1.8 project, because readonly_fields should not contain string 'user_link', but a reference to defined function:

class ProfileAdmin(admin.ModelAdmin):
    # https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
    def user(obj):
        change_url = reverse('admin:auth_user_change', args=(obj.user.id,))
        return mark_safe('<a href="{0}">{1}</a>'.format(change_url, obj.user.email))
    user.short_description = 'Edit linked user'
    raw_id_fields = ('user',)
    list_display = (user, 'last_name', 'first_name', 'specialization',)
    list_display_links = ('first_name', 'last_name', ,)
    readonly_fields = (user, 'user',)

Note that user(obj) overrides both single model edit and model list display for Profile.user field. Note also that readonly_fields uses both user and 'user', one renders linked email, another one user name.

打小就很酷 2024-10-31 04:40:59

我创建了一些 mixin:

# base.py
from django.urls import reverse
from django.utils.html import format_html

def base_method_factory(field_name):
    def base_method(obj):
        try:
            model = getattr(
                obj,
                field_name,
            )
            app_label = model._meta.app_label
            model_name = model._meta.model_name
        except AttributeError as e:
            return None
        return format_html(
            '<a href="{0}">{1}</a> ',
            reverse('admin:%s_%s_change' % (app_label, model_name), args=[model.id]),
            str(model),
        )

    return base_method

class ReadonlyLinkMixin(object):
    def __init__(self, *args, **kwargs):
        self.create_linked_fields()
        super().__init__(*args, **kwargs)

    def create_linked_fields(self):
        linked_fields = filter(lambda name: name.endswith('_linked'), self.readonly_fields)
        for linked_field in linked_fields:
            setattr(
                self,
                linked_field,
                base_method_factory(linked_field.rpartition('_')[0])
            )

# models.py

class SomeModel(models.Model):
    ...
    task = models.FK(...)

# some_app_admin.py

@admin.register(SomeModel)
class SomeModelAdmin(
    ReadonlyLinkMixin,
    admin.ModelAdmin,
):
    fields = (
        ...
        'task_linked',
    )
    readonly_fields = (
        ...
        'task_linked',
    )

所以在管理页面中它将看起来像链接字符串。

I created some mixin:

# base.py
from django.urls import reverse
from django.utils.html import format_html

def base_method_factory(field_name):
    def base_method(obj):
        try:
            model = getattr(
                obj,
                field_name,
            )
            app_label = model._meta.app_label
            model_name = model._meta.model_name
        except AttributeError as e:
            return None
        return format_html(
            '<a href="{0}">{1}</a> ',
            reverse('admin:%s_%s_change' % (app_label, model_name), args=[model.id]),
            str(model),
        )

    return base_method

class ReadonlyLinkMixin(object):
    def __init__(self, *args, **kwargs):
        self.create_linked_fields()
        super().__init__(*args, **kwargs)

    def create_linked_fields(self):
        linked_fields = filter(lambda name: name.endswith('_linked'), self.readonly_fields)
        for linked_field in linked_fields:
            setattr(
                self,
                linked_field,
                base_method_factory(linked_field.rpartition('_')[0])
            )

# models.py

class SomeModel(models.Model):
    ...
    task = models.FK(...)

# some_app_admin.py

@admin.register(SomeModel)
class SomeModelAdmin(
    ReadonlyLinkMixin,
    admin.ModelAdmin,
):
    fields = (
        ...
        'task_linked',
    )
    readonly_fields = (
        ...
        'task_linked',
    )

So in admin page it will look as linked string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文