在我遇到错误的例子之前总结一下,等等:我正在尝试创建一个应用程序,我不必在所有模型中编写代码来限制当前登录帐户的选择(我'我没有使用Auth或内置功能进行帐户或登录。)
即,我不想要做这样的事情:
class Ticket(models.Model):
account = models.ForeignKey(Account)
client = models.ForeignKey(Client) # A client will be owned by one account.
content = models.CharField(max_length=255)
class TicketForm(forms.ModelForm):
class Meta:
model = Ticket
exclude = ('account',) #First sign of bad design?
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
if self.initial.get('account'):
# Here's where it gets ugly IMHO. This seems almost
# as bad as hard coding data. It's not DRY either.
self.fields['client'].queryset = Client.objects.filter(account=self.initial.get('account'))
我的想法是使用以下自定义管理器创建Account(models.Model)
模型,并使用所有模型的多表继承对其进行子类化。它给了我一个巨大的脑痛。我还需要在每个型号上使用account
外键吗?我可以访问某个模型实例的父类帐户吗?
class TicketManager(models.Manager):
def get_query_set(self):
return super(TicketManager, self).get_query_set().filter(account=Account.objects.get(id=1))
# Obviously I don't want to hard code the account like this.
# I want to do something like this:
# return super(ProductManager, self).get_query_set().filter(account=self.account)
# Self being the current model that's using this manager
# (obviously this is wrong because you're not inside a model
# instance , but this is where the confusion comes in for me.
# How would I do this?).
请忽略任何明显的语法错误。我在这里输入了这一切。
我有理由这样做:Django Namespace project
答案 0 :(得分:7)
Django有两个密切相关的问题。
一个是行级权限,其中用户/帐户需要特定权限才能查看表中的特定行(对象),而不是具有表级权限的普通Django auth框架< / em>的
您链接到的项目是尝试实现行权限的几个项目之一。 django-granular-permissions是另一个,第三个(我最喜欢,最活跃/最常用)是django-authority。
即将发布的Django 1.2将有一些钩子可以让行级权限更容易实现,author of django-authority will work on integrating his project。
第二个相关问题是称为多租户数据库,它是行权限的变体。在此方案中,您可能拥有来自单个公司的多个用户,例如,所有用户都可以访问该公司的数据,但不能访问其他公司(租户)。
我认为这不是你想要的,但你可以使用一些相同的技术。请参阅how to enforce account separation in Django和multi-tenant django applications。两者都有非常稀疏的答案,但它们是一个起点,同时也是Rails应用和this article的多租户架构。
至于您问题的更具体的答案,我认为您应该使用django-authority或编写自定义管理器并在开发期间使用record ownership screener来验证您的查询是否绕过自定义管理器。
答案 1 :(得分:2)
这里的基本问题是,即使您不使用django.contrib.auth
,有关当前登录用户的信息仅在视图中可用,也从不在模型中,因为此信息绑定到请求。所以你总是要在视图中做这样的事情:
def some_view(request):
account = get_account_by_request(request)
然后您可以使用该帐户过滤模型。你总是可以通过使用中间件或装饰器使这种方法更加优雅,但要注意它不会太棘手。您的设计可能会在意外点(在我身上发生)中断,因为与继承的管理器等有太多的遗传。保持简单和可预测。
答案 2 :(得分:1)
为了让当前用户进入您的代码,您可以使用threadlocals middleware,但没有任何关于这一点,只有一个大黑客,所以请注意:)
就个人而言,我认为将这种逻辑放入模型中是不好的,因为它们只是数据,不应该知道这些事情。