自定义Django管理员更改表单Foreignkey以包括查看记录

自定义Django管理员更改表单Foreignkey以包括查看记录,django,django-admin,django-widget,Django,Django Admin,Django Widget,在django admin change表单中选择foreignkey时,我试图在添加记录的加号旁边添加一个可以查看记录的href 我试图让href呈现的是,我将admins def render复制到我自己的自定义窗口小部件文件中,并将其添加到其中并对其进行子类化: widgets.py class RelatedFieldWidgetWrapperLink(RelatedFieldWidgetWrapper): def render(self, name, value, *args

在django admin change表单中选择foreignkey时,我试图在添加记录的加号旁边添加一个可以查看记录的href

我试图让href呈现的是,我将admins def render复制到我自己的自定义窗口小部件文件中,并将其添加到其中并对其进行子类化:

widgets.py

class RelatedFieldWidgetWrapperLink(RelatedFieldWidgetWrapper):

    def render(self, name, value, *args, **kwargs):
        rel_to = self.rel.to
        info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
        try:
            related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)
        except NoReverseMatch:
            info = (self.admin_site.root_path, rel_to._meta.app_label, rel_to._meta.object_name.lower())
            related_url = '%s%s/%s/add/' % info
        self.widget.choices = self.choices
        output = [self.widget.render(name, value, *args, **kwargs)]
        if self.can_add_related:
            # TODO: "id_" is hard-coded here. This should instead use the correct
            # API to determine the ID dynamically.
            output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
                (related_url, name))
            output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
            output.append(u'<a href="%s" class="testing" id="add_id_%s" onclick="#"> ' % \        
                        (related_url, name))
        return mark_safe(u''.join(output))
但是,我得到以下错误:

打字错误 init()至少接受4个参数(给定1个)


以前有人遇到过这个问题吗?

相关字段WidgetWrapper小部件和您的子类不打算用作
表单字段覆盖中的小部件。
\uuuu init\uuu
方法具有不同的函数签名,因此
类型错误

如果查看中的代码,可以看到
RelatedFieldWidgetWrapper
小部件在模型管理员的
formfield\u for\u dbfield
方法中实例化,以便可以将参数
rel
管理员站点
可以添加相关的

我认为您可能必须重写模型管理类“
formfield”for_dbfield
方法,并在那里使用自定义的
RelatedFieldWidgetWrapperLink
小部件

class YourModelAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        <snip>
        # ForeignKey or ManyToManyFields
        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
            # Combine the field kwargs with any options for formfield_overrides.
            # Make sure the passed in **kwargs override anything in
            # formfield_overrides because **kwargs is more specific, and should
            # always win.
            if db_field.__class__ in self.formfield_overrides:
                kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs)

            # Get the correct formfield.
            if isinstance(db_field, models.ForeignKey):
                formfield = self.formfield_for_foreignkey(db_field, request, **kwargs)
            elif isinstance(db_field, models.ManyToManyField):
                formfield = self.formfield_for_manytomany(db_field, request, **kwargs)

            # For non-raw_id fields, wrap the widget with a wrapper that adds
            # extra HTML -- the "add other" interface -- to the end of the
            # rendered output. formfield can be None if it came from a
            # OneToOneField with parent_link=True or a M2M intermediary.
            if formfield and db_field.name not in self.raw_id_fields:
                related_modeladmin = self.admin_site._registry.get(
                                                        db_field.rel.to)
                can_add_related = bool(related_modeladmin and
                            related_modeladmin.has_add_permission(request))
                # use your custom widget
                formfield.widget = RelatedFieldWidgetWrapperLink(
                            formfield.widget, db_field.rel, self.admin_site,
                            can_add_related=can_add_related)

            return formfield
        <snip>

我稍微改进了@Alasdair解决方案:

from django.contrib.admin.templatetags import admin_static
from django.core import urlresolvers
from django.utils import safestring
from django.utils.translation import ugettext_lazy as _

class LinkedSelect(widgets.Select):
    def render(self, name, value, attrs=None, *args, **kwargs):
        output = [super(LinkedSelect, self).render(name, value, attrs=attrs, *args, **kwargs)]

        model = self.choices.field.queryset.model
        try:
            obj = model.objects.get(id=value)
            change_url = urlresolvers.reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.object_name.lower()), args=(obj.pk,))
            output.append(u'<a href="%s" class="change-object" id="change_id_%s"> ' % (change_url, name))
            output.append(u'<img src="%s" width="10" height="10" alt="%s"/></a>' % (admin_static.static('admin/img/icon_changelink.gif'), _('Change Object')))
        except (model.DoesNotExist, urlresolvers.NoReverseMatch):
            pass

        return safestring.mark_safe(u''.join(output))

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {models.ForeignKey: {'widget': LinkedSelect}}
来自django.contrib.admin.templatetags导入管理\u静态
从django.core导入URL解析程序
从django.utils导入安全字符串
从django.utils.translation导入ugettext\u lazy作为_
类LinkedSelect(widgets.Select):
def render(self、name、value、attrs=None、*args、**kwargs):
输出=[super(LinkedSelect,self).render(名称,值,attrs=attrs,*args,**kwargs)]
model=self.choices.field.queryset.model
尝试:
obj=model.objects.get(id=value)
change\u url=urlresolvers.reverse('管理员:%s\u%s\u更改'%(obj.\u meta.app\u标签,obj.\u meta.object\u name.lower()),args=(obj.pk,))
output.append(u'%(admin\u static.static('admin/img/icon\u changelink.gif'),u('Change Object'))
除了(model.DoesNotExist、urlresolvers.NoReverseMatch):
通过
返回safestring。标记_safe(u“”。连接(输出))
类YourModelAdmin(admin.ModelAdmin):
formfield_overrides={models.ForeignKey:{'widget':LinkedSelect}

它使用与
RelatedFieldWidgetWrapper
相同的代码结构和样式。此外,它使用“更改”图标,而不仅仅是字符串。当外键指向任何地方或外键指向未定义管理接口的模型时,它会正常存活。

运行顶部代码块会给出
NameError:request未定义
,因此需要
request=kwargs['request']
。另外,
formfield\u for_blah
行中间不需要请求,因为它们都有
**kwargs
,其中包含请求。@dustynachos该代码基于Django 1.3,它确实调用了
self.formfield\u for_foreignkey(db\u field,request,**kwargs)
。如果答案不适用于Django的最新版本,请随意编辑。
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.forms.widgets import Select

def get_admin_change_url(obj):
    ct = ContentType.objects.get_for_model(obj)
    change_url_name = 'admin:%s_%s_change' % (ct.app_label, ct.model)
    return reverse(change_url_name, args=(obj.id,))

class LinkedSelect(Select):
    def render(self, name, value, attrs=None, *args, **kwargs):
        output = super(LinkedSelect, self).render(name, value, attrs=attrs, *args, **kwargs)
        model = self.choices.field.queryset.model
        try:
            id = int(value)
            obj = model.objects.get(id=id)
            view_url = get_admin_change_url(obj)
            output += mark_safe('&nbsp;<a href="%s" target="_blank">view</a>&nbsp;' % (view_url,))
        except model.DoesNotExist:
            pass
        return output

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {models.ForeignKey:{'widget':LinkedSelect}}
from django.contrib.admin.templatetags import admin_static
from django.core import urlresolvers
from django.utils import safestring
from django.utils.translation import ugettext_lazy as _

class LinkedSelect(widgets.Select):
    def render(self, name, value, attrs=None, *args, **kwargs):
        output = [super(LinkedSelect, self).render(name, value, attrs=attrs, *args, **kwargs)]

        model = self.choices.field.queryset.model
        try:
            obj = model.objects.get(id=value)
            change_url = urlresolvers.reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.object_name.lower()), args=(obj.pk,))
            output.append(u'<a href="%s" class="change-object" id="change_id_%s"> ' % (change_url, name))
            output.append(u'<img src="%s" width="10" height="10" alt="%s"/></a>' % (admin_static.static('admin/img/icon_changelink.gif'), _('Change Object')))
        except (model.DoesNotExist, urlresolvers.NoReverseMatch):
            pass

        return safestring.mark_safe(u''.join(output))

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {models.ForeignKey: {'widget': LinkedSelect}}