【问题标题】:Making Django Readonly ForeignKey Field in Admin Render as a Link使管理员中的 Django Readonly ForeignKey 字段呈现为链接
【发布时间】:2011-07-16 21:07:38
【问题描述】:

我在 Django 的管理员中公开了一个模型,它使用 ModelAdmin 的 readonly_fields 列表来显示一个“用户”字段,这是一个链接到 Django 用户模型的 ForiegnKey。默认情况下,readonly_fields 使该字段呈现为包含用户电子邮件的简单文本(例如someuser@domain.com)。我将如何更改它以呈现为该用户的关联管理页面的链接? (例如<a href="/admin/auth/user/123/">someuser@domain.com</a>

【问题讨论】:

    标签: python django django-admin


    【解决方案1】:

    深入研究源代码,我发现您基本上可以将自己的字段定义为您的 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'
    

    【讨论】:

    • 这实际上是有记录的,尽管是间接的:readonly_fields 的部分说它“行为与 ModelAdmin.list_display 几乎相同”,并带有指向定义自定义方法选项的list_display 的链接。
    • user_link.allow_tags = True 而不是mark_safe 然后这个方法也适用于变更列表。
    • 如果你链接到其他类型,通常是urlresolvers.reverse('admin:&lt;app&gt;_&lt;type&gt;_change', ...)。将 替换为适当的字符串。
    • 优雅的解决方案 :o) 唯一的缺点是使用默认管理模板时,所有只读字段都放在更改表单的底部。
    【解决方案2】:

    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 使用 user 和 'user',一个呈现链接的电子邮件,另一个呈现用户名。

    【讨论】:

      【解决方案3】:

      我创建了一些 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>&nbsp;',
                  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',
          )
      

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

      【讨论】:

        猜你喜欢
        • 2019-02-03
        • 2010-10-06
        • 2022-11-08
        • 2011-08-14
        • 1970-01-01
        • 2015-09-10
        • 2011-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多