为用户提供添加SQL约束的能力,Django

时间:2011-11-04 16:32:00

标签: django django-models django-admin django-orm

我有一个奇怪的需求,一位客户要我实施一个webapp来支持他的数据库。因为我喜欢Django,所以我决定使用它。

我遇到的额外需求如下:用户应该有额外的“权力”来创建模型约束,例如检查IntegerField的范围,所有这些都不知道Python的任何内容。

所以,我有一些想法,但我不确定(如果有的话)是正确的。这是我的想法:

  1. 使用JavaScript实现模板端验证
  2. 实现Python脚本和用户友好的方式来使用它来编写models.py文件(听起来很糟糕)
  3. 使用原始SQL CHECK约束编写一些管理操作,但我仍然不知道如何
  4. 这个请求是否可以解决?你能给我一个最简单的方法吗?

    提前致谢,

    - 弗拉维奥

1 个答案:

答案 0 :(得分: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()
    
  3. 因此,在您的观看中,您可以像这样使用它:YourModel.c.get_constrainted_query(user)

    请注意,我没有测试此代码,但我希望您已经掌握了这个概念。

    要覆盖ModelAdmin中的查询,请使用thisthis技术。