Entfernen „hinzufügen eine andere“ in Django Admin-Bildschirm
-
19-09-2019 - |
Frage
Jedes Mal, wenn ich bin der Bearbeitung Objekt A mit einem Fremdschlüssel zu Objekt B, ein Plus Option „Einen weiteren hinzufügen“ neben den Wahlen von Objekt B zur Verfügung Wie kann ich diese Option entfernen?
konfigurierte ich einen Benutzer ohne Rechte Objekt B. Der hinzuzufügen Pluszeichen sind noch verfügbar, aber wenn ich darauf klicken, es heißt „Zugriff verweigert“. Es ist hässlich.
Ich verwende Django 1.0.2
Lösung
DEPRECATED ANTWORT
Django hat da dies möglich.
Haben Sie stattdessen mit CSS einfach nicht zeigen, die Taste in Betracht gezogen? Vielleicht ist das ein wenig zu hacky.
Dies ist nicht getestet, aber ich denke ...
no-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 Doc, dies zu tun - Medien als eine statische Definition
Hinweis / Edit: Die Dokumentation sagt, dass die Dateien mit dem MEDIA_URL vorangestellt werden, aber in meinem Experiment ist es nicht. Ihre Ergebnisse können variieren.
Wenn Sie feststellen, dies ist der Fall für Sie, gibt es eine schnelle Lösung für dieses ...
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',) }
Andere Tipps
(Stop upvoting diese falsche Antwort !!!)
ERRATA : Diese Antwort ist im Grunde falsch, und antwortet nicht OPs Frage. Siehe unten.
(dies gilt nur für Inline-Formen ist, keine Fremdschlüsselfelder als OP gefragt)
Einfachere Lösung, kein CSS Hack, keine Bearbeitung Django Codebasis:
Fügen Sie diese auf Ihre Inline-Klasse:
max_num=0
UPDATE
Diese antwortet nicht OPs Frage und ist nur sinnvoll, die „add related“ Taste für die Inline-Formulare zu verstecken, und keine Fremdschlüssel wie gewünscht geplant.
Als ich schrieb diese Antwort, IIRC die akzeptierte Antwort verbergen beide, weshalb ich verwirrt wurde.
Die folgenden Links scheinen eine Lösung zu schaffen (wenn auch versteckt CSS mit den am ehesten machbar Dinge scheint zu tun, besonders, wenn die „weitere hinzufügen“ -Buttons von FKs in Inline-Formen):
Django 1.7 Entfernen Schaltfläche Hinzufügen von Inline-Form
Obwohl die meisten der Lösungen hier Arbeit erwähnt, gibt es eine andere sauberer Weg, es zu tun. Wahrscheinlich in einer späteren Version von Django wurde eingeführt, nachdem die anderen Lösungen vorgestellt wurden. (Ich verwende derzeit Django 1.7)
Um die "weitere hinzufügen" Option,
entfernenclass ... #(Your inline class)
def has_add_permission(self, request):
return False
Ebenso, wenn Sie deaktivieren möchten „löschen?“ Option, fügen Sie die folgende Methode in Inline-Klasse.
def has_delete_permission(self, request, obj=None):
return False
N. B. Arbeitet für django 1.5.2 und möglicherweise älter. Die can_add_related
Eigenschaft erschien vor etwa 2 Jahren .
Der beste Weg, die ich gefunden habe ist Ihre Modeladmin der get_form Funktion außer Kraft zu setzen. In meinem Fall wollte ich den Autor eines Beitrags zwingen, die aktuell angemeldeten Benutzers zu sein. Code unten mit reichlich Kommentaren. Die wirklich wichtige Bit ist die Einstellung von 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
Der interessante Teil der Änderungen hier in get_form
zu machen ist, dass author.widget
ist eine Instanz von django.contrib.admin.widgets.RelatedFieldWidgetWrapper
wo als ob Sie versuchen, und Änderungen in einen der formfield_for_xxxxx
Funktionen, das Widget eine Instanz der tatsächlichen Form Widget ist, in diesem typischen ForeignKey Fall ist es ein django.forms.widgets.Select
.
Schauen Sie sich django.contrib.admin.options.py
und überprüfen Sie die BaseModelAdmin
Klasse, formfield_for_dbfield
Methode.
Sie werden sehen, diese:
# 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)
Ich denke, Ihre beste Wette ist, Unterklasse von ModelAdmin
erstellen (die wiederum eine Unterklasse von BaseModelAdmin
ist), stützen Sie Ihr Modell auf dieser neuen Klasse, überschreiben formfield_fo_dbfield
und machen es so, dass es nicht / oder wird bedingt das Widget wickeln in RelatedFieldWidgetWrapper
.
Man könnte argumentieren, dass, wenn Sie einen Benutzer, die keine Rechte ähnliche Objekte hinzugefügt haben, sollte die RelatedFieldWidgetWrapper
nicht den Add-Link angezeigt werden? Vielleicht ist dies etwas, das der Erwähnung verdient in Django trac ?
Ich verwende die folgenden Ansätze für Form und InlineForm
Django 2.0, Python 3 +
Form
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
Inline-Formular
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
Die Antwort von @Slipstream zeigt wie , um die Lösung zu implementieren, nämlich. durch zwingende die Attribute für das Formularfeld des Widgets, aber meiner Meinung nach ist get_form
nicht die logischste Ort, dies zu tun.
Die Antwort von @cethegeek zeigt mit , um die Lösung zu implementieren, nämlich. in einer Verlängerung von formfield_for_dbfield
, aber kein explizites Beispiel liefern.
Warum Gebrauch formfield_for_dbfield
? Seine docstring schlägt vor, dass es ist der designierte Haken mit Formularfeldern für messing:
Haken zur Angabe der Form Feldinstanz für eine bestimmte Datenbank Feldinstanz.
Es ermöglicht auch (etwas) saubere und klaren Code, und als Bonus, können wir leicht zusätzliche Form Field
gesetzt Attribute wie initial
Wert und / oder disabled
(Beispiel hier ), indem man sich auf den kwargs
(vor dem Aufruf super
) hinzugefügt wird.
Also, die Kombination der beiden Antworten (vorausgesetzt, die OP Modelle sind ModelA
und ModelB
und das ForeignKey
Modellfeld heißt 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)
Hinweis: Wenn das ForeignKey
Modellfeld on_delete=models.CASCADE
hat, das can_delete_related
Attribut ist False
standardmäßig wie in der Quelle RelatedFieldWidgetWrapper
.
Ich verwende Django 2.x und ich glaube, ich beste Lösung gefunden, zumindest für meinen Fall.
Die HTML-Datei auf „Speichern und weiteren hinzufügen“ auf your_python_installation\Lib\site-packages\django\contrib\admin\templates\admin\subtmit_line.html
ist.
- Kopieren, dass HTML-Datei und fügen Sie ihn in Ihr Projekt wie so
your_project\templates\admin\submit_line.html
. - Öffnen Sie es und Kommentar / den Tastencode löschen, wie gewünscht:
{#{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}#}
Ich weiß, dass dieses Problem bereits beantwortet. Aber vielleicht jemand in der Zukunft mit mir einen ähnlichen Fall hat.
Basierend auf cethegeek Antwort habe ich diese:
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 Install Dir) /django/contrib/admin/widgets.py: Kommentar alles zwischen Linie 239 und Linie 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')))