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

Python 如何在Django admin中显示多个关系的原始id值?,python,django,django-admin,Python,Django,Django Admin,我有一个应用程序在ForeignKeyField和ManyToManyField上都使用原始id。管理员在编辑框的右侧显示外键的值 不幸的是,它对很多人都不起作用。我已经检查了代码,我认为这是正常的行为。然而,我想知道是否有人有一个简单的提示来改变这种行为 提前谢谢 更新:我试图对manytomanyrawidget进行子类化,但我不知道如何说原始id字段应该使用我的自定义小部件。formfield\u覆盖似乎无法与原始id字段一起工作最后,我成功地使其工作。这是更新的Django2.0版本 f

我有一个应用程序在ForeignKeyField和ManyToManyField上都使用原始id。管理员在编辑框的右侧显示外键的值

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

提前谢谢


更新:我试图对manytomanyrawidget进行子类化,但我不知道如何说原始id字段应该使用我的自定义小部件。formfield\u覆盖似乎无法与原始id字段一起工作

最后,我成功地使其工作。这是更新的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.contrib.admin.widgets导入manytomanyrawidget
从django.utils.encoding导入智能\u str
从django.url反向导入
从django.utils.html导入转义,标记_safe
类VerboseManyToManyRawidget(ManyToManyRawidget):
"""
用于在“原始id”界面中显示多个id的小部件
显示用户友好的值,如ForeignKeyRawId小部件
"""
定义初始化(self,remote,attrs=None,*args,**kwargs):
super()
def标签_和_url_表示_值(self,value):
价值=价值
str_值=[]
field=self.rel.get\u related\u field()
key=field.name
fk_模型=self.rel.model
app\u label=fk\u模型。\u meta.app\u label
class_name=fk_model._meta.object_name.lower()
对于值中的_值:
尝试:
obj=fk_model._default_manager.using(self.db).get(**{key:the_value})
url=reverse('admin:{0}{1}}{change'。格式(应用程序标签,类名称),args=[obj.id])
标签=转义(智能(obj))
elt=''.format(
网址,
'onclick=“return showAddAnotherPopup(this);“target=“\u blank””,
标签
)
str_值+=[elt]
除fk_model.DoesNotExist外:
str_值+=[u'???']
返回mark_safe(','.join(str_值)),''
类MyAdmin(admin.ModelAdmin):
...
def formfield_for_dbfield(self,db_字段,**kwargs):
如果('groups',)中的db_field.name:
kwargs['widget']=verbosemanyTomanyRawidget(db_field.remote_field,self.admin_site)
其他:
返回super()
kwargs.pop('请求')
返回db_field.formfield(**kwargs)
不幸的是,我白白花了一笔赏金;-)


更新:此代码段现在与Django 2.0兼容。另请参见

这适用于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.contrib.admin.sites导入站点
从django.contrib.admin.widgets导入manytomanyrawidget
从django.core.urlResolver导入反向,NoReverseMatch
从django.utils.safestring导入标记_safe
类VerboseManyToManyRawidget(ManyToManyRawidget):
def标签_和_url_表示_值(self,value):
结果=[]
对于v值:
key=self.rel.get_-related_-field().name
尝试:
obj=self.rel.model.\u default\u manager.using(self.db).get(**{key:v})
除了(ValueError,self.rel.model.DoesNotExist):
返回“”,“”
尝试:
url=反向(
“{}:{}{}{}{}}{u change.”格式(self.admin\u site.name,obj.\u meta.app\u标签,
obj.\u meta.object\u name.lower()),
args=(obj.pk,))
除NoReverseMatch外:
url=''#管理员未为目标模型注册。
result.append(''.format(url,str(obj)))
返回mark_safe(“;”。连接(结果)),“”
类VerboseRawIdManyToManyAdminMixin:
def formfield_for_dbfield(self,db_字段,**kwargs):
如果self.raw\u id\u字段中的db\u field.name:
kwargs.pop('请求',无)
如果db_field.rel.\uuuuuu class.\uuuuuuu name\uuuuuu=='ManyToManyRel':
kwargs['widget']=verbosemanyTomanyRawidget(db_field.rel,site)
返回db_field.formfield(**kwargs)
返回super()
还有Django应用程序可用于此目的