5

我正在尝试为用户提供一个界面,以便在数据库上编写自定义查询。我需要确保他们只能查询他们被允许的记录。为了做到这一点,我决定使用django-guardian应用基于行的访问控制。

这是我的模式的样子

class BaseClass(models.Model):
    somefield = models.TextField()
    class Meta:
        permissions = (
            ('view_record', 'View record'),
        )

class ClassA(BaseClass):
    # some other fields here
    classb = models.ForeignKey(ClassB)

class ClassB(BaseClass):
    # some fields here
    classc = models.ForeignKey(ClassC)

class ClassC(BaseClass):
    # some fields here

我希望能够使用get_objects_for_group如下:

>>> group = Group.objects.create('some group')
>>> class_c = ClassC.objects.create('ClassC')
>>> class_b = ClassB.objects.create('ClassB', classc=class_c)
>>> class_a = ClassA.objects.create('ClassA', classb=class_b)
>>> assign_perm('view_record', group, class_c)
>>> assign_perm('view_record', group, class_b)
>>> assign_perm('view_record', group, class_a)
>>> get_objects_for_group(group, 'view_record')

这给了我一个查询集。我可以使用上面定义的 BaseClass 并针对其他相关类编写原始查询吗?

>>> qs.intersection(get_objects_for_group(group, 'view_record'), \
                    BaseClass.objects.raw('select * from table_a a'
                                          'join table_b b on a.id=b.table_a_id '
                                          'join table_c c on b.id=c.table_b_id '
                                          'where some conditions here'))

这种方法有意义吗?有没有更好的方法来解决这个问题?

谢谢!

编辑:

解决该问题的另一种方法可能是为每个用户创建一个单独的表。我了解这可能会增加我的应用程序的复杂性,但是:

  • 用户数长期不会超过100s。不是消费者应用程序。
  • 根据我们的用例,我不太可能需要跨这些表进行查询。我不会编写需要从 table1、table2、table3 聚合属于同一模型的任何内容的查询。
  • 为每个客户维护一个单独的表可能具有优势。

您认为这是一种可行的方法吗?

4

3 回答 3

3

在研究了许多选项后,我发现我可以使用PostgreSQL 上的行级安全性在数据库级别解决这个问题。它最终成为最简单和最优雅的。

这篇文章帮助我将应用程序级别的用户与 PostgreSQL 策略联系起来。

我通过研究了解到:

  • 将来,当客户可能会影响彼此的查询性能时,单独的表仍然是一种选择,因为他们被允许运行任意查询。

  • 如果您打算使用原始查询或临时查询,尝试在 ORM 级别解决它几乎是不可能的。

于 2017-11-28T21:51:29.773 回答
2

我想你已经知道你需要做什么了。您正在寻找的词是多租户。虽然不是每个客户一张桌子。最适合您的是每个客户一个模式。不幸的是,我所拥有的关于多租户的最佳文章已不复存在。查看是否可以找到缓存版本:https ://msdn.microsoft.com/en-us/library/aa479086.aspx否则互联网上有大量文章可用。

另一种可行的方法是查看自定义管理器。您可以为每个 Model-Customer 编写一个自定义管理器并相应地对其进行查询。但这一切都会导致应用程序的复杂性,并且很快就会失控。应用程序安全层中的任何错误对您来说都是一场噩梦。

权衡两者,我倾向于说您在编辑中所说的多租户解决方案是迄今为止最好的方法。

于 2017-11-28T12:15:26.273 回答
-1

首先,您应该向我们提供更多详细信息,您的架构是如何使用 django 设置和构建的,以便我们为您提供帮助。你实现了 API 吗?如果您正在构建大型应用程序,消耗大量数据,那么使用 django 模板并不是一个好主意。因为这会极大地影响查询负载。我建议您从后端提取前端。

于 2017-11-30T07:15:25.483 回答