Python 向django admin添加每个对象的权限

Python 向django admin添加每个对象的权限,python,django,django-admin,Python,Django,Django Admin,背景 我正在为一个度假租赁网站开发django应用程序。它将有两种类型的用户,租客和物业经理 我希望物业经理能够在django admin中管理他们的租赁物业。但是,他们应该只能管理自己的财产 我意识到默认的django管理员不支持这一点。我想知道添加这个功能会有多麻烦,如果可行的话,最好的处理方法是什么 目标 理想情况下,我想象它是这样工作的: vacation | rental | Can add rental vacation | rental | Can change rental v

背景

我正在为一个度假租赁网站开发django应用程序。它将有两种类型的用户,租客和物业经理

我希望物业经理能够在django admin中管理他们的租赁物业。但是,他们应该只能管理自己的财产

我意识到默认的django管理员不支持这一点。我想知道添加这个功能会有多麻烦,如果可行的话,最好的处理方法是什么


目标

理想情况下,我想象它是这样工作的:

vacation | rental | Can add rental vacation | rental | Can change rental vacation | rental | Can delete rental
auth
已经允许这样的权限:

vacation | rental | Can add rental vacation | rental | Can change rental vacation | rental | Can delete rental 假期|租金|可以增加租金 假期|租金|可以更改租金 假期|租金|可以删除租金 我想将此更改为:

vacation | rental | Can add any rental vacation | rental | Can change any rental vacation | rental | Can delete any rental vacation | rental | Can add own rental vacation | rental | Can change own rental vacation | rental | Can delete own rental 假期|租金|可以添加任何租金 假期|租金|可以更改任何租金 假期|租赁|可以删除任何租赁 度假|租赁|可以添加自己的租赁 度假|租赁|可以更改自己的租赁 假期|租赁|可以删除自己的租赁
可能的解决方案

框架如何决定租金(或任何东西)是否属于用户?我想它会检查
vacation.Rental
类,看看它是否有一个
ForeignKey
auth.User
(可能有一些特定的名字,比如“owner”)

  • 在创建新的
    休假.租赁时,
    ForeignKey
    字段的值将强制为当前用户的id。
    ForeignKey
    字段将不会显示在表单上

  • 在列出rentals时,仅显示与当前用户匹配的
    ForeignKey
    的rentals

  • 在更改租金时,仅显示与当前用户匹配的
    外键
    租金。
    ForeignKey
    字段将不会显示在表单上

当然,这应该能够适用于任何具有适当的
ForeignKey
字段的模型,而不仅仅是我们的
vacation.rent
模型

到目前为止,这听起来是可行的,还是我应该走另一个方向


并发症

现在,这里是棘手的部分;我不知道该怎么办。假设一个
Rental
可以有很多“RentalPhoto”。
RentalPhoto
有一个
ForeignKey
Rental
。用户应该能够将照片添加到自己的租赁中。但是,这些照片没有用户
ForeignKey
,因此无法直接找出照片的所有者

这可以通过框架中的一些诡计来解决吗,在
ForeignKey
s之后,直到找到一个对象,并向用户提供
ForeignKey
?或者我应该采取简单的方法,将
RentalPhoto
(以及属于
rent
的所有其他内容)自己的
ForeignKey
交给相应的
auth.User
?第二种方法将导致不必要的冗余,第一种方法可能需要不必要的处理开销

如果我完全误入歧途,请毫不犹豫地为我指出正确的方向。提前感谢您的帮助

这个问题可以通过一些诡计来解决吗 框架,遵循外键 直到找到具有 用户的外键

我看不出哪里有必要耍花招: RentalPhoto->租赁->用户 因此,要获取特定RentalPhoto的用户,您可以在实例中调用类似的内容:

photo.rental.user

在一个步骤中遵循多个关系可以被视为非欺骗。

我只需在每个模型中添加一个方法
由(用户)
拥有,由模型决定它是否由该用户拥有。在大多数情况下,
是由
拥有的,可以是基本模型类中的通用函数,在特殊情况下可以对其进行调整。e、 g

class RentalPhoto(BaseModel):
    def is_owned_by(self, user):
        return self.rental.is_owned_by(user)
这是足够通用的,并且是明确的,你将完全控制事物的行为

要添加新权限,您可以将其添加到您的模型中,例如

class Rental(models.Model):
    # ...
    class Meta:
        permissions = (
            ("can_edit_any", "Can edit any rentals"),
        )
我认为不应该为
any
own
添加两个权限,而应该只添加
own
权限,这样每个对象都已经有
can\u edit
,您可以将其视为用户只能编辑其对象,并且如果用户有权限只能编辑任何对象,那么他就可以编辑所有对象

使用这个,我们可以通过添加一个自定义后端来扩展auth

class PerObjectBackend(ModelBackend):

    def has_perm(self, user_obj, perm, obj=None):
        allowed = ModelBackend.has_perm(self, user_obj, perm)
        if perm.find('any') >=0 :
            return allowed

        if perm.find('edit') >=0 or perm.find('delete') >=0:
            if obj is None:
                raise Exception("Perm '%s' needs an object"%perm)
            if not obj.is_owned_by(user_obj):
                return False

        return allowed

这是一个非常快速的实现,实际上,您可以扩展权限对象来检查它是否需要和对象,例如
权限。is_per_对象
,而不是执行粗略的字符串搜索,但是如果您有标准名称,如果您不想实现自己的权限后端,这也应该起作用,我建议你使用“你将以一种更简单的方式做你想做的事情”。

这是一种很好的方法

基本上,您可以为模型创建自定义管理类,并定义方法
get\u queryset
。在您的情况下,它可能是如下所示。超级用户将看到所有的租金,而所有者只有他的

class RentalAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(RentalAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(owner=request.user)

这是另一个可能的线索:

这将适用于这种特殊情况,但我想以一种通用的方式来做--“当然,这应该能够适用于任何具有适当的
ForeignKey
字段的模型,而不仅仅是我们的
休假.rent
[和相关的]模型。”有很多种可能的方法更通用。例如,拥有一个model.Ownable,它定义了字段所有者,并在Ownable模型中对其进行了扩展。这个答案没有多大帮助。这使得大部分问题没有答案。也许我在解释这个问题上做得不好?如果你能告诉我为什么使用模型继承对你的案例没有帮助,我会更好地理解你的问题所在。谢谢你,Anurag;它不像我想的那样通用,但我会考虑的。如何将其绑定到
auth
中,以便显示我的新权限