删除"另外添加"在Django管理屏幕
-
19-09-2019 - |
题
每当我和你的编辑的对象一个与外国的关键目B,加选项"添加一个"可用接下来的选择的对象B。我怎么删除该选项吗?
我配置的用户没有权利增加对象B。加号是仍然可用,但是,当我点击,它说,"许可拒绝"。这是丑陋的.
我使用的Django1.0.2
解决方案
DEPRECATED ANSWER
Django的自使之成为可能。
你有没有考虑,而不是使用CSS来根本不显示按钮?也许这是一个有点哈克。
这是未经测试,但我想...
无addanother-button.css
#_addanother { display: none }
admin.py
class YourAdmin(admin.ModelAdmin):
# ...
class Media:
# edit this path to wherever
css = { 'all' : ('css/no-addanother-button.css',) }
Django的文件这样做的 - 媒体作为静态定义
注意/编辑:的文件说,这些文件将与MEDIA_URL预先考虑,但在我的实验事实并非如此。大小可能不同。
如果你发现这是你的情况下,有这种速战速决...
class YourAdmin(admin.ModelAdmin):
# ...
class Media:
from django.conf import settings
media_url = getattr(settings, 'MEDIA_URL', '/media/')
# edit this path to wherever
css = { 'all' : (media_url+'css/no-addanother-button.css',) }
其他提示
(停止upvoting这个错误答案!!!)
勘误表:这个答案基本上是错误的,不回答OP的问题。见下文。
(这是仅适用于内联形式,OP要求不外键字段)
简单的解决方案,没有CSS破解,没有编辑Django的基本代码:
添加到您的在线类:
max_num=0
<强>更新强>
这不回答OP的问题,按要求是仅仅是为了掩盖“添加相关”按钮内嵌的形式,而不是外键有用。
在我写这个答案,这个都接受的答案都隐藏,这就是为什么我弄糊涂了。
以下链接似乎提供了解决方案(尽管使用CSS隐藏似乎是最可行的事情要做,特别是如果以串联形式“添加其他” FKS的按钮):
虽然大多数在这里提到的解决方案的工作,有是做它的另一个更清洁的方式。有人大概在Django的更高版本推出,其他的解决措施后。 (我目前使用Django 1.7)
要去除 “添加其他” 选项,
class ... #(Your inline class)
def has_add_permission(self, request):
return False
同样的,如果你想禁用“删除?”选项,添加以串联类下面的方法。
def has_delete_permission(self, request, obj=None):
return False
N.B。适用于Django的1.5.2和可能更老。该can_add_related
财产出现大约2年前。
我发现最好的办法是重写你的ModelAdmin的get_form功能。在我的情况,我想强制帖子的作者是当前登录的用户。用大量的评论下面的代码。真正重要的位是widget.can_add_related
的设置:
def get_form(self,request, obj=None, **kwargs):
# get base form object
form = super(BlogPostAdmin,self).get_form(request, obj, **kwargs)
# get the foreign key field I want to restrict
author = form.base_fields["author"]
# remove the green + by setting can_add_related to False on the widget
author.widget.can_add_related = False
# restrict queryset for field to just the current user
author.queryset = User.objects.filter(pk=request.user.pk)
# set the initial value of the field to current user. Redundant as there will
# only be one option anyway.
author.initial = request.user.pk
# set the field's empty_label to None to remove the "------" null
# field from the select.
author.empty_label = None
# return our now modified form.
return form
在这里做出的变化get_form
有趣的部分是,author.widget
是django.contrib.admin.widgets.RelatedFieldWidgetWrapper
的一个实例,其中,如果你尝试,并在的formfield_for_xxxxx
功能的一个变化,小部件的实际表单控件的一个实例,在这个典型的ForeignKey的情况下,它是一个django.forms.widgets.Select
。
看django.contrib.admin.options.py
并检查了BaseModelAdmin
类,formfield_for_dbfield
方法。
您将看到:
# 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:
formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
我认为最好的方法是创建ModelAdmin
(这又是BaseModelAdmin
的子类)的子类,立足于新的类,覆盖formfield_fo_dbfield
你的模型,并使它所以它不会/或将有条件地包住小部件在RelatedFieldWidgetWrapper
。
有人可能会说,如果你有没有权利将相关对象的用户,该RelatedFieldWidgetWrapper
不应该显示的添加链接?也许这是这是值得一提中 Django的TRAC ?
我使用以下方法的表格和<强> InlineForm 强>
2.0的Django,Python的3 +
<强>表格强>
class MyModelAdmin(admin.ModelAdmin):
#...
def get_form(self,request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
user = form.base_fields["user"]
user.widget.can_add_related = False
user.widget.can_delete_related = False
user.widget.can_change_related = False
return form
<强>内嵌表格强>
class MyModelInline(admin.TabularInline):
#...
def get_formset(self, request, obj=None, **kwargs):
formset = super().get_formset(request, obj, **kwargs)
user = formset.form.base_fields['user']
user.widget.can_add_related = False
user.widget.can_delete_related = False
user.widget.can_change_related = False
return formset
答案 @滑 表示 如何 实施解决方案,即。由压倒一切的属性formfield的部件,但是,在我看来, get_form
是不是最合乎逻辑的地方做到这一点。
答案 @cethegeek 表示 哪里 实施解决方案,即。在扩展的 formfield_for_dbfield
, 但没有提供一个明确的例子。
为什么使用 formfield_for_dbfield
?它的 文档字符串 表明,它指定钩搞乱的形式领域:
钩,用于指定的形式领域的实例,对于给定的数据库领域的实例。
它还允许(略)清洁和更明确的代码,而且,作为奖励,我们可以很容易地设置额外的形式 Field
属性, 如 initial
值和/或 disabled
(例 在这里,),通过增加他们的 kwargs
(话之前 super
).
因此,结合两个答案(假定该运的模型 ModelA
和 ModelB
, , ForeignKey
模型领域的命名 b
):
class ModelAAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, request, **kwargs):
# optionally set Field attributes here, by adding them to kwargs
formfield = super().formfield_for_dbfield(db_field, request, **kwargs)
if db_field.name == 'b':
formfield.widget.can_add_related = False
formfield.widget.can_change_related = False
formfield.widget.can_delete_related = False
return formfield
# Don't forget to register...
admin.site.register(ModelA, ModelAAdmin)
注:如果的 ForeignKey
模型领域已 on_delete=models.CASCADE
, , can_delete_related
属性 False
默认情况下,可以看出在 来源 对于 RelatedFieldWidgetWrapper
.
我使用的Django2.x和我想我找到最好的解决办法,至少对我的情况。
HTML文件"保存和另外添加"按钮上 your_python_installation\Lib\site-packages\django\contrib\admin\templates\admin\subtmit_line.html
.
- 复制那html文件和粘贴到项目一样
your_project\templates\admin\submit_line.html
. - 打开它,并评论/删除的按钮的代码如所期望的:
{#{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}#}
我知道这个问题已经回答。但也许有人在今后有类似情况下的跟我来。
class SomeAdmin(admin.ModelAdmin):
form = SomeForm
def formfield_for_dbfield(self, db_field, **kwargs):
formfield = super(SomeAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'some_m2m_field':
request = kwargs.pop("request", None)
formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # for foreignkey: .formfield_for_foreignkey
wrapper_kwargs = {'can_add_related': False, 'can_change_related': False, 'can_delete_related': False}
formfield.widget = admin.widgets.RelatedFieldWidgetWrapper(
formfield.widget, db_field.remote_field, self.admin_site, **wrapper_kwargs
)
return formfield
django.contrib.admin.widgets.py
(Django的安装目录)/django/contrib/admin/widgets.py:评论一切线239&244之间的线:
if rel_to in self.admin_site._registry: # If the related object has an admin interface:
# 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')))