2016-01-11 91 views
0

我們使用django-MPTT樹項目,當樹項目被修改時,我必須創建自動電子郵件通知的功能。絕對直接使用保存信號,但是 - 如果修改了父項,則n(n代表孩子數+父項)發送電子郵件,而不僅僅發送一次(因爲父母的更改會自動完成給孩子)。有沒有一種很好的方法來防止這種情況發生,並基本告訴Django「每個模型只能發送一封郵件」?如何讓Django每個模型只運行一次命令

最好的我想出了一種哈克的方式(和一個非常糟糕的破解):添加一個模型到數據庫中,當父項修改時更新,並且兒童總是先檢查該模型發送郵件。即如果HiddenModel存在,請勿發送電子郵件,否則發送電子郵件。等5秒後(可能在另一個線程中)刪除/撤消對該對象的修改。這可能會起作用,但是在性能方面,這與所有這些數據庫查詢都是不好的。

編輯:型號:(縮短的版本爲SO,可能有這種形式的一些錯誤)

從mptt.models進口MPTTModel,TreeForeignKey

class TreeItem(MPTTModel): 
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children') 

    users = models.ManyToManyField('accounts.User', blank=True) 

    name = models.CharField(max_length=255) 

    @property 
    def tree_path(self): 
     if self.is_root_node(): 
      return [] 

     tree = self.get_ancestors(include_self=False, ascending=False) 
     return list(map(lambda item: item.name, tree)) 

    def save(self, *args, **kwargs): 
     is_new = self.pk is None 
     if not is_new: 
      prev_allowed_users = TreeItem.objects.get(pk=self.pk).users.all() 

     super().save(*args, **kwargs) 

     new_allowed_users = self.users.all() 
     if is_new: 
      self.send_access_email(list(new_allowed_users)) #TODO 
     else: 
      if prev_allowed_users != new_allowed_users: 
       send_to = self.get_new_access_users(prev_allowed_users, new_allowed_users) # TODO 
       self.send_access_email(send_to) 

    def get_new_access_users(self, prev_users, new_users): 
     send_to = [] 
     for user in new_users: 
      if user not in prev_users: 
       send_to.append(user) 

     return send_to 

    def send_access_email(self, recipient_list): 

     email_content = 'example' 

     email = EmailMessage(
      'subject', 
      email_content, 
      '[email protected]', 
      recipient_list) 

     print("Sending email to %s users" % str(len(recipient_list))) 
+0

你可以發佈你的模型?我想我可以非常直觀地描述你所描述的內容,但總是有助於將它展現在我面前。 – Travis

+0

@Travis更新了問題。 – makaveli

+0

如果使用實際的post_save信號而不是重寫save()方法,它是否仍然傳播給所有的孩子? –

回答

0

你需要某種形式的登記弄清楚如果你的對象被保存在外部或作爲樹遍歷級聯的一部分。看起來,使用類變量可能是一個更優雅的方法。這裏有一些僞代碼來說明我的意思。

 
class TreeItem(MPTTModel): 
    _save_registry = set() 

    ... your model fields go here ... 

    def is_save_locked(self): 
     return any(p.id in TreeItem._save_registry for p in self.get_parents()) 

    def save_lock(self): 
     TreeItem._save_registry.add(self.id) 

    def save_release(self): 
     TreeItem._save_registry.remove(self.id) 

    def save(self, *args, **kwargs): 
     if not self.is_save_locked: 
      self.save_lock() 
      ... do things only original save should do ... 
      self.save_release() 
     ... do things every save should do ... 
     return super(TreeItem, self).save(*args, **kwargs) 
相關問題