2013-03-04 23 views
11

cancellare ho admin.py come segue:Django admin: override di metodo

class profilesAdmin(admin.ModelAdmin): 
    list_display = ["type","username","domain_name"] 

Ora voglio eseguire alcune azioni prima di eliminare l'oggetto:

class profilesAdmin(admin.ModelAdmin): 
    list_display = ["type","username","domain_name"] 

    @receiver(pre_delete, sender=profile) 
    def _profile_delete(sender, instance, **kwargs): 
     filename=object.profile_name+".xml" 
     os.remove(os.path.join(object.type,filename)) 

Se uso cancellare metodo del segnale come questo ricevo un errore dicendo che self dovrebbe essere il primo parametro.

Come posso modificare la funzione sopra descritta?
E voglio recuperare il nome_profilo dell'oggetto da eliminare. Come si può fare?

Ho provato anche l'override metodo delete_model:

def delete_model(self, request, object): 
    filename=object.profile_name+".xml" 
    os.remove(os.path.join(object.type,filename)) 
    object.delete() 

Ma questo dosn't lavoro se più oggetti devono essere cancellati in un solo colpo.

+0

Ancora ottengo l'auto errore non definito – arjun

risposta

5

Sei sulla strada giusta con il tuo metodo delete_model. Quando l'amministratore di django esegue un'azione su più oggetti contemporaneamente usa lo update function. Tuttavia, come si vede nei documenti queste azioni vengono eseguite a livello di database solo utilizzando SQL.

È necessario aggiungere il proprio metodo delete_model come custom action nell'admin di django.

def delete_model(modeladmin, request, queryset): 
    for obj in queryset: 
     filename=obj.profile_name+".xml" 
     os.remove(os.path.join(obj.type,filename)) 
     obj.delete() 

Allora aggiungi la tua funzione per il vostro ModelAdmin -

class profilesAdmin(admin.ModelAdmin): 
    list_display = ["type","username","domain_name"] 
    actions = [delete_model] 
+0

cosa è make_published? – arjun

+0

whoops, copia e incolla errore - Ho aggiornato la mia risposta. –

+0

Questo genera un errore se si desidera eliminare solo un oggetto. Fornisce l'oggetto error'_profile 'non è iterable. Anche l'elenco delle azioni avrà 2 valori. Uno è delete_model e l'altro elimina i profili selezionati. – arjun

0

Il tuo metodo dovrebbe essere

class profilesAdmin(admin.ModelAdmin): 
    #... 

    def _profile_delete(self, sender, instance, **kwargs): 
     # do something 

    def delete_model(self, request, object): 
     # do something 

si dovrebbe aggiungere un riferimento all'oggetto corrente come primo argomento in ogni firma del metodo (di solito chiamato self). Inoltre, delete_model dovrebbe essere implementato come metodo.

+0

No, non è possibile. Se aggiungo io, ottengo l'errore _profile_delete richiede 3 argomenti (2 dati) – arjun

4

Il problema principale è che l'eliminazione di massa dell'amministratore di Django utilizza SQL, non instance.delete(), come indicato altrove. Per una soluzione solo admin, la seguente soluzione preserva l'interstitial dell'amministratore di Django "vuoi veramente eliminarli".

La soluzione più generale è sostituire il set di query restituito dal gestore del modello per intercettare l'eliminazione.

from django.contrib.admin.actions import delete_selected 

class BulkDeleteMixin(object): 
    class SafeDeleteQuerysetWrapper(object): 
     def __init__(self, wrapped_queryset): 
      self.wrapped_queryset = wrapped_queryset 

     def _safe_delete(self): 
      for obj in self.wrapped_queryset: 
       obj.delete() 

     def __getattr__(self, attr): 
      if attr == 'delete': 
       return self._safe_delete 
      else: 
       return getattr(self.wrapped_queryset, attr) 

     def __iter__(self): 
      for obj in self.wrapped_queryset: 
       yield obj 

     def __getitem__(self, index): 
      return self.wrapped_queryset[index] 

     def __len__(self): 
      return len(self.wrapped_queryset) 

    def get_actions(self, request): 
     actions = super(BulkDeleteMixin, self).get_actions(request) 
     actions['delete_selected'] = (BulkDeleteMixin.action_safe_bulk_delete, 'delete_selected', ugettext_lazy("Delete selected %(verbose_name_plural)s")) 
     return actions 

    def action_safe_bulk_delete(self, request, queryset): 
     wrapped_queryset = BulkDeleteMixin.SafeDeleteQuerysetWrapper(queryset) 
     return delete_selected(self, request, wrapped_queryset) 

class SomeAdmin(BulkDeleteMixin, admin.ModelAdmin): 
    ... 
1

si tenta l'override metodo delete_model fallito perché quando si eliminano più oggetti il ​​Django utilizzano QuerySet.delete(), per il metodo delete() di ragioni di efficienza il vostro modello non sarà chiamato.

si può vedere che ci https://docs.djangoproject.com/en/1.9/ref/contrib/admin/actions/
guardare l'inizio di avviso

Admin delete_model() è lo stesso come delete() https://github.com/django/django/blob/master/django/contrib/admin/options.py#L1005

in modo che quando si eliminano più oggetti, è personalizzato il metodo di eliminazione sarà mai chiamata del modello .

si ha due vie.

1. azione di eliminazione personalizzata.
azione chiamata Model.delete() per ciascuno degli elementi selezionati.

2. segnale di utilizzo.
è possibile utilizzare il segnale da solo, non all'interno della classe.

è anche possibile assistere a questa domanda Django model: delete() not triggered