【问题标题】:Giving user the power to add SQL constraints, Django赋予用户添加 SQL 约束的权力,Django
【发布时间】:2011-12-22 04:39:50
【问题描述】:

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

我有困难的额外需求如下:用户应该有额外的“权力”来创建模型约束,比如检查 IntegerField 的范围,所有这些都不需要了解 Python。

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

  1. 使用 JavaScript 实现模板端验证
  2. 实现一个 Python 脚本和一种用户友好的方式来使用它来编写 models.py 文件(这听起来很糟糕)
  3. 使用原始 SQL CHECK 约束编写一些管理操作,但我仍然不知道如何

这个请求可以解决吗?你能告诉我最简单的方法吗?

提前致谢,

-- 弗拉维奥

【问题讨论】:

  • 我不会推荐 javascript 来解决这个问题。就性能而言,这是一个糟糕的主意,至少如果您希望查询集中有数百或数千个项目。

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


【解决方案1】:

是的,确实有可能。我们将使用custom object managerdynamic Q objects 来解决这个问题。这是一个例子。

  1. 创建适当的模型来存储有关约束的信息。请注意,我们为 ContentType 创建 ForeginKey 是为了将我们的约束绑定到特定的模型类。

    #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 技术。

【讨论】:

    猜你喜欢
    • 2011-12-31
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多