2010-07-19 5 views
9

Sto tentando di implementare uno schema di cancellazione post ritardo del blog. Quindi, invece di un fastidioso Sei sicuro?, si ottiene un intervallo di tempo di 2 minuti per annullare la cancellazione.Come utilizzare un __init__ personalizzato di una classe di modello Python per un motore di app correttamente?

voglio monitorare cosa verranno eliminati quando con una classe db.Model (DeleteQueueItem), come ho trovato alcun modo per eliminare un'attività dalla coda e sospettano posso interrogare cosa c'è.

Creazione di un DeleteQueueItem un'entità dovrebbe impostare automaticamente un delete_when proprietà e aggiungere un compito alla coda. Uso il relativo percorso dei post del blog come nome_chiave e desidero utilizzarlo come nome_chiave anche qui. Questo mi ha portato a una consuetudine init:

class DeleteQueueItem(db.Model): 
    """Model to keep track of items that will be deleted via task queue.""" 

    # URL path to the blog post is handled as key_name 
    delete_when = db.DateTimeProperty() 

    def __init__(self, **kwargs): 
     delay = 120 # Seconds 
     t = datetime.timedelta(seconds=delay) 
     deadline = datetime.datetime.now() - t 
     key_name = kwargs.get('key_name') 

     db.Model.__init__(self, **kwargs) 
     self.delete_when = deadline 

     taskqueue.add(url='/admin/task/delete_page', 
         countdown=delay, 
         params={'path': key_name}) 

Questo sembra funzionare, fino a quando provo a cancellare l'entità:

fetched_item = models.DeleteQueueItem.get_by_key_name(path) 

questo viene a mancare con:

TypeError: __init__() takes exactly 1 non-keyword argument (2 given) 

Cosa am Sto sbagliando?

risposta

15

In genere, non provare a sovrascrivere il metodo init delle classi Model. Mentre è possibile ottenere il giusto, il comportamento corretto del costruttore è abbastanza complesso e può persino cambiare tra le versioni, rompendo il codice (anche se cerchiamo di evitare di farlo!). Parte del motivo è che il costruttore deve essere utilizzato sia dal proprio codice, per costruire nuovi modelli, sia dal framework, per ricostituire i modelli caricati dal datastore.

Un approccio migliore consiste nell'utilizzare un metodo factory, che si chiama al posto del costruttore.

Inoltre, probabilmente si desidera aggiungere l'attività nello stesso momento in cui si scrive l'entità, piuttosto che al momento della creazione. In caso contrario, si finisce con una condizione di competizione: l'attività può essere eseguita prima di aver memorizzato la nuova entità sul datastore!

Ecco un refactoring suggerito:

class DeleteQueueItem(db.Model): 
    """Model to keep track of items that will be deleted via task queue.""" 

    # URL path to the blog post is handled as key_name 
    delete_when = db.DateTimeProperty() 

    @classmethod 
    def new(cls, key_name): 
     delay = 120 # Seconds 
     t = datetime.timedelta(seconds=delay) 
     deadline = datetime.datetime.now() - t 

     return cls(key_name=key_name, delete_when=deadline) 

    def put(self, **kwargs): 
     def _tx(): 
     taskqueue.add(url='/admin/task/delete_page', 
         countdown=delay, 
         params={'path': key_name}, 
         transactional=True) 
     return super(DeleteQueueItem, self).put(**kwargs) 
     if not self.is_saved(): 
     return db.run_in_transaction(_tx) 
     else: 
     return super(DeleteQueueItem, self).put(**kwargs) 
+0

Grande, grazie! Un problema con questo, dove ho difficoltà a pensare ad una soluzione elegante, è che delay e key_name non sono disponibili in def _tx(), però. – thorwil

+0

Oops, buon punto. Puoi definire 'ritardo' come membro della classe (ad esempio, al livello superiore), poiché sembra essere una costante e il nome della chiave può essere utilizzato come self.key(). Name(). –

+0

Fatto funzionare! ritardo come membro della classe era abbastanza chiaro, ma non sarei mai arrivato a self.key(). name(). Grazie ancora! – thorwil

Problemi correlati