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

War es hilfreich?

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,

entfernen
class ... #(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.

  1. Kopieren, dass HTML-Datei und fügen Sie ihn in Ihr Projekt wie so your_project\templates\admin\submit_line.html.
  2. Ö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')))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top