2010-07-19 3 views
9

Я пытаюсь реализовать отложенную схему удаления блога. Так что вместо раздражающего Вы уверены?, вы получите 2-минутный временной интервал для отмены удаления.Как правильно использовать пользовательский __init__ класса приложения Python?

Я хочу, чтобы отслеживать, что будут удалены Когда с db.Model класса (DeleteQueueItem), так как я не нашел способ, чтобы удалить задание из очереди и подозреваю, что я могу запросить, что там.

Создание DeleteQueueItem объекта должен автоматически установить delete_when свойства и добавить задачу в очередь. Я использую относительный путь сообщений в блогах как их key_name и хочу использовать это как key_name здесь тоже. Это привело меня к пользовательской инициализации:

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

Это похоже на работу, пока я пытаюсь удалить объект:

fetched_item = models.DeleteQueueItem.get_by_key_name(path) 

Это терпит неудачу с:

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

Что я Я делаю неправильно?

ответ

15

Как правило, вы не должны пытаться переопределять метод классов 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() 

    @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

Отлично, спасибо! Проблема с этим, когда мне сложно думать об элегантном решении, заключается в том, что задержка и key_name недоступны в def _tx(). – thorwil

+0

Упс, хорошая точка. Вы можете определить «задержка» как член класса (например, на верхнем уровне), поскольку он является константой, а к имени ключа можно обращаться как self.key(). Name(). –

+0

Получил это на работу! поскольку член класса был достаточно ясным, но я бы никогда не пришел к self.key(). name(). Еще раз спасибо! – thorwil

Смежные вопросы