Django:如何组织这一大模型/管理器/设计混乱?

发布于 2024-08-19 19:23:41 字数 1909 浏览 6 评论 0原文

在我进入不好的例子之前总结一下,等:我正在尝试制作一个应用程序,我不必在所有模型中编写代码来限制对当前登录帐户的选择(我没有使用身份验证,或帐户或登录的内置功能)。

即,我不想必须做这样的事情:

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命名空间项目

To sum things up before I get into bad examples, et al: I'm trying to make an application where I don't have to write code in all my models to limit choices to the current logged in account (I'm not using Auth, or builtin features for the account or login).

ie, I don't want to have to do something like this:

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'))

My idea is to create an Account(models.Model) model with the following custom manager, and subclass it using multi-table inheritance with all of my models. It's giving me a huge brain ache though. Will I still need an account foreign key on each model? Can I access the parent class account for a certain model instance?

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?).

Please ignore any blaring syntax errors. I typed this whole thing in here.

Here's where I got the idea to do this: Django Namespace project

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你的笑 2024-08-26 19:23:41

谈到 Django 有两个密切相关的问题。

一种是行级权限,其中用户/帐户需要特定权限才能查看表中的特定行(对象),而不是具有表级权限的普通 Django 身份验证框架。

您链接到的项目是尝试实现行权限的几个项目之一。 django-细粒度-permissions 是另一个也是第三个(我最喜欢的,也是最活跃/维护的)是 django-authority

即将发布的 Django 1.2 将具有使行级权限更容易实现的钩子,并且 django-authority 的作者将致力于集成他的项目

第二个相关问题是所谓的“多租户数据库”,它是行权限的变体。例如,在此方案中,您可能拥有来自一家公司的多个用户,他们都有权访问该公司的数据,但不能访问其他公司(租户)的数据。

我认为这不是您正在寻找的,但您也许可以使用一些相同的技术。请参阅如何在 Django 中强制执行帐户分离多租户 django 应用程序。两者都有非常稀疏的答案,但都是一个起点,以及查看 Rails 应用程序的多租户架构和 这篇文章

至于您问题的更具体答案,我认为您应该使用 django-authority 或编写自定义管理器并在开发过程中使用记录所有权筛选器来验证您的查询是否正确不要绕过自定义管理器。

There are two closely related problems when it comes to Django.

One is row level permissions where users/accounts need specific permission to view a specific row (object) in a table, as opposed to normal Django auth framework which has table level permissions.

The project you linked to is one of several projects trying to implement row permissions. django-granular-permissions is another and a third (my favorite and the most active/maintained) is django-authority.

The upcoming release of Django 1.2 will have hooks making row-level permissions easier to implement, and the author of django-authority will work on integrating his project.

The second related problem is something called multi-tenant database which is a variation on row permissions. In this scheme you might have multiple users from a single company, for example, who all have access to data for that company but not other companies (tenants).

I don't think this is what you're looking for but you might be able to use some of the same techniques. See how to enforce account separation in Django and multi-tenant django applications. Both have really sparse answers but are a starting point as well as looking at multi-tenant architecture for Rails apps and this article.

As for a more specific answer to your question I think you should either use django-authority or write a custom manager and use the record ownership screener during development to verify your queries aren't bypassing the custom manager.

寒江雪… 2024-08-26 19:23:41

这里的基本问题是,即使您不使用 django.contrib.auth ,有关当前登录用户的信息也只能在视图中使用,而不能在模型中使用,因为此信息是绑定的到一个请求。因此,您始终必须在视图中执行以下操作:

def some_view(request):
    account = get_account_by_request(request)

然后您可以使用该帐户来过滤模型。您始终可以通过使用中间件或装饰器使这种方法更加优雅,但请注意它不会变得太棘手。由于继承管理器等的多重继承过多,您的设计可能会在意想不到的点(发生在我身上)中断。保持简单且可预测。

The basic problem here is, even though you don't use django.contrib.auth that information about the current logged in user is only available in the view and never in the model, because this information is bound to a request. So you will always have to do something like this in the view:

def some_view(request):
    account = get_account_by_request(request)

Then you can use the account to filter models. You can always make this approach more elegant by using a middleware or a decorator but beware that it doesn't get too tricky. Your design might break at unexpected points (happened to me) because of too much multiple inheritances with inherited managers and the like. Keep it simple and predictable.

装纯掩盖桑 2024-08-26 19:23:41

为了让当前用户进入您的代码,您可以使用 threadlocals 中间件,但没有任何奇特的事情,只是一个大黑客,所以要小心:) 就

我个人而言,我认为将这种逻辑放入模型中是不好的,因为它们只是数据,不应该意识到这些事情。

In order to get current user into your code, you can use threadlocals middleware but there isn't anything fancy about that, just one big hack, so watch out :)

Personally, i think it's bad to put that kind of logic into models, because they're just data and should not be aware of such things.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文