Domanda

Ogni volta che sto modificando l'oggetto A con una chiave esterna di opporsi B, l'opzione più "aggiungere un altro" è disponibile accanto alle scelte di oggetto B. Come faccio a rimuovere tale opzione?

Ho configurato un utente senza diritti per aggiungere l'oggetto B. Il segno più è ancora disponibile, ma quando lo scatto sopra, si dice "Permesso negato". E 'brutto.

sto usando Django 1.0.2

È stato utile?

Soluzione

RISPOSTA DEPRECATO

Django da allora ha reso possibile tutto questo.


Avete considerato invece utilizzare i CSS per semplicemente non visualizzare il pulsante? Forse è un po 'troppo hacky.

Questa non è testato, ma sto pensando ...

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 per fare questo - media come definizione statica

Nota / Edit: La documentazione dice che i file verranno prefissati con la MEDIA_URL ma nella mia sperimentazione non lo è. La vostra situazione potrebbe essere diversa.

Se trovate questo è il caso per voi, c'è una soluzione rapida per questo ...

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',) }

Altri suggerimenti

(fermata upvoting questa risposta sbagliata !!!)

ERRATA : Questa risposta è fondamentalmente sbagliata, e non risponde alla domanda di OP. Vedi sotto.

  

(questo è applicabile solo a inline forme, non campi di chiave esterna come chiesto OP)

     

soluzione più semplice, senza trucco CSS, nessuna modifica Django codebase:

     

Aggiungi questo alla classe Inline:

     

max_num=0

Aggiorna

Questo non risponde alla domanda del PO, ed è utile per nascondere i "add correlate" pulsante per le forme in linea, e non solo le chiavi esterne come richiesto.

Quando ho scritto questa risposta, IIRC la risposta accettata nascondere sia, che è il motivo per cui mi sono confuso.

I seguenti collegamenti sembra fornire una soluzione (anche se nascosto usando i CSS sembra le cose più fattibili da fare, soprattutto se il "aggiungere un altro" pulsanti di FKS in moduli inline):

Django 1.7 rimozione pulsante Aggiungi dalla forma in linea

Anche se la maggior parte delle soluzioni di cui qui funziona, c'è un altro modo più pulito di farlo. Probabilmente è stato introdotto in una versione successiva di Django, dopo che le altre soluzioni sono state presentate. (Sto attualmente utilizzando Django 1.7)

Per rimuovere il "Aggiungere un'altra opzione",

class ... #(Your inline class)

    def has_add_permission(self, request):
        return False

Allo stesso modo, se si desidera disattivare "Delete?" opzione, aggiungere il seguente metodo della classe Inline.

    def has_delete_permission(self, request, obj=None):
        return False

NB. Opere per Django 1.5.2 e forse più anziani. La proprietà can_add_related apparso circa 2 anni fa.

Il modo migliore che ho trovato è quello di ignorare la funzione get_form del ModelAdmin. Nel mio caso ho voluto forzare l'autore di un post per essere l'utente attualmente connesso. Codice qui sotto con i commenti copiose. Il bit veramente importante è l'impostazione di 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

La parte interessante di apportare le modifiche qui a get_form è che author.widget è un'istanza di django.contrib.admin.widgets.RelatedFieldWidgetWrapper dove come se si cerca di apportare modifiche in una delle funzioni formfield_for_xxxxx, il widget è un'istanza del widget attuale forma, in questo tipico ForeignKey caso si tratta di un django.forms.widgets.Select.

Guarda django.contrib.admin.options.py e controllare la classe BaseModelAdmin, metodo formfield_for_dbfield.

Si vedrà questo:

# 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)

Credo che la cosa migliore è creare sottoclasse di ModelAdmin (che a sua volta è una sottoclasse di BaseModelAdmin), basare il proprio modello su quella nuova classe, formfield_fo_dbfield override e fare in modo che non sarà / o che condizionalmente avvolgere il widget in RelatedFieldWidgetWrapper.

Si potrebbe sostenere che se si dispone di un utente che non dispone dei diritti per l'aggiunta di oggetti correlati, il RelatedFieldWidgetWrapper non dovrebbe visualizzare il link aggiungi? Forse questo è qualcosa che è degno di menzione in Django trac ?

Io uso i seguenti approcci per la Modulo e InlineForm

Django 2.0, Python 3 +

Modulo

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 Modulo

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

La risposta da @Slipstream spettacoli come per implementare la soluzione, vale a dire. sovrascrivendo gli attributi per il widget del formfield, ma, a mio parere, get_form non è il posto più logico per fare questo.

La risposta da @cethegeek spettacoli , dove per implementare la soluzione, vale a dire. un prolungamento della formfield_for_dbfield, ma non fornisce un esempio esplicito.

Perché usare formfield_for_dbfield? Il suo docstring suggerisce che è il gancio designata per scherzi con campi modulo:

  

Agganciare per specificare l'istanza modulo campo per una determinata istanza di database Field.

Ciò consente inoltre di (leggermente) codice più pulito e più chiara, e, come bonus, possiamo facilmente impostare ulteriore forma Field attributi , come valore initial e / o disabled (esempio qui ), aggiungendoli al kwargs (prima di chiamare super).

Quindi, combinando le due risposte (assumendo modelli del OP sono ModelA e ModelB, e il campo Modello ForeignKey prende il nome 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)

Nota: se il campo Modello ForeignKey ha on_delete=models.CASCADE, l'attributo can_delete_related è False di default, come si può vedere nella fonte per RelatedFieldWidgetWrapper.

Sto usando Django 2.xe Credo di avere trovato la soluzione migliore, almeno per il mio caso.

Il file HTML per la "Salva e aggiungere un altro" tasto è in your_python_installation\Lib\site-packages\django\contrib\admin\templates\admin\subtmit_line.html.

  1. Copiare il file html e incollarlo al progetto in questo modo your_project\templates\admin\submit_line.html.
  2. aprirlo e commentare / cancellare il codice del pulsante, se lo desideri:

{#{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}#}

So che questo problema è già una risposta. Ma forse qualcuno in futuro avere un caso simile con me.

In base a risposta cethegeek ho fatto questo:

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: Commento tutto tra Linea 239 & Line 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')))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top