2010-07-19 11 views
9

Estoy intentando implementar un esquema de eliminación de publicación de blog diferido. Entonces, en lugar de un molesto ¿Estás seguro?, obtiene un marco de tiempo de 2 minutos para cancelar la eliminación.¿Cómo usar __init__ personalizado de una clase de modelo Python de motor de aplicación correctamente?

quiero seguir lo que se eliminarán cuando con una clase db.Model (DeleteQueueItem), ya que no he encontrado ninguna manera de eliminar una tarea de la cola y se sospecha que pueda consultar lo que hay.

Creación de una entidad DeleteQueueItemdebería establecer automáticamente una delete_when propiedad y añadir una tarea a la cola. Utilizo la ruta relativa de las publicaciones de blog como key_name y quiero usar eso como key_name aquí también. Esto me llevó a un inicio personalizada :

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

Esto parece funcionar, hasta que lo intente eliminar la entidad:

fetched_item = models.DeleteQueueItem.get_by_key_name(path) 

esta falla con:

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

Qué am Estoy haciendo mal?

Respuesta

15

En general, no debe intentar y anular el método de init de las clases de modelo. Si bien es posible hacerlo bien, el comportamiento correcto del constructor es bastante complejo, e incluso puede cambiar entre lanzamientos, rompiendo su código (¡aunque tratemos de evitar hacerlo!). Parte de la razón para esto es que el constructor debe ser utilizado tanto por su propio código, para construir nuevos modelos, como por el marco, para reconstituir los modelos cargados desde el almacén de datos.

Un mejor enfoque es utilizar un método de fábrica, que se llama en lugar del constructor.

Además, es probable que desee agregar la tarea al mismo tiempo que escribe la entidad, en lugar de en el momento de la creación. Si no lo haces, terminas con una condición de carrera: ¡la tarea puede ejecutarse antes de que hayas almacenado la nueva entidad en el almacén de datos!

Aquí hay una refactorización sugerido:

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, gracias! Un problema con eso, donde me cuesta pensar en una solución elegante, es que el retraso y el nombre de la clave no están disponibles en def _tx(), sin embargo. – thorwil

+0

Vaya, buen punto. Puede definir 'demora' como un miembro de la clase (por ejemplo, en el nivel superior), ya que parece ser una constante, y se puede acceder al nombre de la clave como self.key(). Name(). –

+0

¡Lo tengo para trabajar! demora como miembro de la clase fue lo suficientemente claro, pero nunca hubiera llegado a self.key(). name(). ¡Gracias de nuevo! – thorwil

Cuestiones relacionadas