2011-11-04 16 views
2

我有一個奇怪的需求,一位客戶要求我實現一個webapp來支持他的數據庫。由於我喜歡Django,我決定使用它。給用戶添加SQL約束的能力,Django

我很難處理的額外需求如下:用戶應該有額外的「權力」來創建模型約束,比如檢查IntegerField的範圍,所有這些都不需要了解Python。

所以,我有一些想法,但我不知道什麼是(如果有)是正確的。這裏是我的想法:

  1. 使用JavaScript
  2. 實現一個Python腳本,並使用它用戶友好的方式寫入models.py文件(這聽起來很可怕)
  3. 編寫管理實現一個模板端驗證使用原始SQL CHECK約束的操作,但我仍不知如何

該請求是否可以解決?你能給我一個關於最簡單的方法嗎?

由於提前,

- 弗拉維奧

+0

我不會推薦JavaScript來解決這個問題。性能方面,這是一個可怕的想法,至少如果你期望在一個查詢集中包含成百上千的項目。 –

回答

1

是的,有可能確實如此。我們將使用custom object managerdynamic Q objects來解決問題。這是一個例子。

  1. 創建一個合適的模型來存儲有關約束的信息。請注意,我們將ForeginKey創建爲ContentType,以便將我們的約束與特定的模型類綁定。

    #your_app/models.py 
    from django.contrib.contenttypes.models import ContentType 
    from django.contrib.auth.models import User 
    
    class PerUserConstraint(models.Model): 
        user = models.ForeignKey(User) 
        content_type = models.ForeignKey(ContentType) 
        field_name = models.CharField(max_length = 255) 
        predicate = models.CharField(max_length = 255) #for example, 'contains' etc. 
        filter_value = models.CharField(max_length = 255) 
    
  2. 創建自定義管理器,將其註冊到模型中。

    #your_app/models.py 
    from django.db.models.query_utils import Q 
    
    class ConstraintedManager(models.Manager): 
        def get_constrainted_query(self, user): 
         qs = self.model.objects.all() 
         content_type = ContentType.objects.get_for_model(self.model.__class__) 
         constraints = PerUserConstraint.objects.filter(
                   user = user, 
                   content_type = content_type 
         ) 
         if constraints: 
          filters = [] 
          for constraint in constraints: 
           filters.append(('%s__%s' % (constraint.field_name, constraint.predicate), constraint.value) 
          # at this point filters should look like this: 
          # [('question__contains', 'dinner'), ('question__contains', 'meal')] 
          q_list = [Q(x) for x in filters] 
          return qs.filter(reduce(operator.and_, q_list)) 
          # which is something like 
          # return qs.filter(Q(question__contains = 'dinner') & Q(question__contains = 'meal')) 
    
         else: 
          return qs  
    
    class YourModel(models.Model): 
        #some fields 
        ... 
        c = ConstraintedManager() 
    

所以你的觀點,你將能夠使用它像這樣:YourModel.c.get_constrainted_query(user)

請注意,我沒有測試此代碼,但我希望你已經掌握的概念。

要覆蓋ModelAdmin內部的查詢,請使用thisthis技術。

+1

這太有意思了,非常感謝你的幫助:) –

+0

不客氣! :))) –