如何在 Django 管理中显示 ManyToMany 关系的 raw_id 值?

发布于 2024-09-01 18:39:58 字数 279 浏览 6 评论 0原文

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

不幸的是,它不适用于ManyToMany。我检查了代码,我认为这是正常行为。但是我想知道是否有人有一个简单的技巧来改变这种行为?

提前致谢

更新:我尝试对 ManyToManyRawIdWidget 进行子类化,但我不知道如何说 raw_id_fields 应该使用我的自定义小部件。 formfield_overrides 似乎不适用于 raw_id 字段

I have an app using raw_id on both ForeignKeyField and ManyToManyField. The admin displays the value of the foreign key on the right of the edit box.

Unfortunatey, it doesn't work with ManyToMany. I've checked the code and I think that it is the normal behavior. However I would like to know if someone has an easy tip to change this behavior?

Thanks in advance

Update: I've tried to subclass the ManyToManyRawIdWidget but I don't know how to say that the raw_id_fields should use my custom widget. formfield_overrides doesn't seem to work with raw_id fields

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

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

发布评论

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

评论(2

溺孤伤于心 2024-09-08 18:39:58

最后我成功地让它发挥作用。这是更新的 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/

Finally I succeed to make it working. Here is the updated Django2.0 version

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)

Unfortunately, I've spend a bounty for nothing ;-)

UPDATE : this snippet is now compatible with Django 2.0. See also http://djangosnippets.org/snippets/2108/

相权↑美人 2024-09-08 18:39:58

这适用于 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-沙门氏菌

This works for Django 1.11 and higher

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)

Also there is Django app for that purpose django-salmonella

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