代码之家  ›  专栏  ›  技术社区  ›  luc

如何在Django admin中显示多个关系的原始\u id值?

  •  5
  • luc  · 技术社区  · 15 年前

    不幸的是,它对很多人都不起作用。我已经检查了代码,我认为这是正常的行为。不过,我想知道是否有人有一个简单的提示,以改变这种行为?

    更新:我已经尝试将manytomanyrawidget子类化,但是我不知道如何说原始id字段应该使用我的自定义小部件。formfield\u覆盖似乎不适用于原始\u id字段

    2 回复  |  直到 15 年前
        1
  •  10
  •   luc    6 年前

    最后我成功地使它工作了。这是最新的Django2.0版本

    from django.contrib.admin.widgets import ManyToManyRawIdWidget
    from django.utils.encoding import smart_str
    from django.urls import reverse
    from django.utils.html import escape, mark_safe
    
    
    class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget):
        """
        A Widget for displaying ManyToMany ids in the "raw_id" interface rather 
        than in a <select multiple> box. Display user-friendly value like the ForeignKeyRawId widget
        """
    
        def __init__(self, remote_field, attrs=None, *args, **kwargs):
            super().__init__(remote_field, attrs, *args, **kwargs)
    
        def label_and_url_for_value(self, value):
            values = value
            str_values = []
            field = self.rel.get_related_field()
            key = field.name
            fk_model = self.rel.model
            app_label = fk_model._meta.app_label
            class_name = fk_model._meta.object_name.lower()
            for the_value in values:
                try:
                    obj = fk_model._default_manager.using(self.db).get(**{key: the_value})
                    url = reverse('admin:{0}_{1}_change'.format(app_label, class_name), args=[obj.id])
                    label = escape(smart_str(obj))
                    elt = '<a href="{0}" {1}>{2}</a>'.format(
                        url,
                        'onclick="return showAddAnotherPopup(this);" target="_blank"',
                        label
                    )
                    str_values += [elt]
                except fk_model.DoesNotExist:
                    str_values += [u'???']
            return mark_safe(', '.join(str_values)), ''
    
    
    class MyAdmin(admin.ModelAdmin):
         ...
         def formfield_for_dbfield(self, db_field, **kwargs):
             if db_field.name in ('groups', ):
                 kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.remote_field, self.admin_site)
             else:
                 return super().formfield_for_dbfield(db_field, **kwargs)
             kwargs.pop('request')
             return db_field.formfield(**kwargs)
    

    不幸的是,我白白花了一笔赏金;-)

    更新:此代码段现在与Django 2.0兼容。另请参见 http://djangosnippets.org/snippets/2108/

        2
  •  1
  •   Mark Mishyn    6 年前

    这适用于Django 1.11及更高版本

    from django.contrib.admin.sites import site
    from django.contrib.admin.widgets import ManyToManyRawIdWidget
    from django.core.urlresolvers import reverse, NoReverseMatch
    from django.utils.safestring import mark_safe
    
    
    class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget):
    
        def label_and_url_for_value(self, value):
            result = []
            for v in value:
                key = self.rel.get_related_field().name
                try:
                    obj = self.rel.model._default_manager.using(self.db).get(**{key: v})
                except (ValueError, self.rel.model.DoesNotExist):
                    return '', ''
    
                try:
                    url = reverse(
                        '{}:{}_{}_change'.format(self.admin_site.name, obj._meta.app_label,
                                                 obj._meta.object_name.lower()),
                        args=(obj.pk,))
                except NoReverseMatch:
                    url = ''  # Admin not registered for target model.
    
                result.append('<strong><a href="{}">{}</a></strong>'.format(url,  str(obj)))
    
            return mark_safe('; '.join(result)), ''
    
    
    class VerboseRawIdManyToManyAdminMixin:
        def formfield_for_dbfield(self, db_field, **kwargs):
            if db_field.name in self.raw_id_fields:
                kwargs.pop('request', None)
                if db_field.rel.__class__.__name__ == 'ManyToManyRel':
                    kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.rel, site)
                return db_field.formfield(**kwargs)
            return super().formfield_for_dbfield(db_field, **kwargs)
    

    也有Django应用程序用于此目的 django-salmonella