2016-05-11 76 views
1

我試圖找到一種方法來在Django模型中存儲函數。 我的用例是一個帶有計劃和有條件發送的電子郵件系統。 「如果約翰還沒有登錄,明天發送此電子郵件」Django,數據庫中的存儲功能

「明天發送此電子郵件。

理想情況下,我想創建帶有測試功能字段的電子郵件。

def my_test(instance): 
    if (now() - instance.user.last_login) > timedelta(days=1): 
    return False 
    return True 

Email(send_later_date=now() + timedelta(days=1), 
     conditional=my_test) 

這裏就是我想

import importlib 

Email(send_later_date=now() + timedelta(days=1), 
     conditional='my_app.views.my_test') 



class Email(models.Model): 
    send_later_date = models.DateTimeField(null=True, blank=True) 
    conditional = models.TextField() 

    def send_email(self): 
    if self.send_later_date < now(): 
     if not self.conditional: 
     function_send_email() 
     else: 
     function_string = self.conditional 
     mod_name, func_name = function_string.rsplit('.',1) 
     mod = importlib.import_module(mod_name) 
     func = getattr(mod, func_name) 
     if func(): 
      function_send_email() 

你會怎麼做呢?我正在考慮將函數名稱存儲在文本字段中。一旦需要,你將如何運行它? ImportLib似乎很有趣......

回答

1

存儲函數名是一個有效的方法,因爲它實際上是pickle module使用的。這有利於(就你而言),如果你更新函數的代碼,它將自動應用於現有的電子郵件(但要注意向後兼容性)。

爲了方便和安全(尤其是如果函數名可能來自用戶輸入),您可能希望將所有這些函數保留在同一模塊中,並且只將函數名稱存儲在數據庫中,而不是完整的導入路徑。所以你可以簡單地導入函數庫並用getattr來讀取它。我想你也會想給這些函數提供參數。如果您不想將自己限制爲給定數量/順序/類型的參數,則可以將字典存儲爲JSON字符串,然後使用**運算符將其展開。

import my_app.func_store as store 
import json 

func = getattr(store, self.conditional) 
params = json.loads(self.conditional_params) 
if func(**params): 
    function_send_email() 
+0

不錯的答案。用戶不能輸入任何功能或代碼,電子郵件都是從代碼中生成的。所以將條件函數放在生成電子郵件的位置附近非常方便。我目前有這個電子郵件應用程序的集中版本,這是一個噩夢來維護。這就是爲什麼我正在研究這個想法.. :-) –