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

Dag*_*bit 14 python django django-admin

背景

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

我希望物业经理能够在django管理员中管理他们的出租物业.但是,他们应该只能管理自己的属性.

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


目标

理想情况下,我认为它的工作方式如下:

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类,看它是否有一个ForeignKeyauth.User(可能有一些特定的名称,如"拥有者").

  • 在创建新的时vacation.Rental,该ForeignKey字段的值将被强制为当前用户的id.该ForeignKey字段不会显示在表单上.

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

  • 在更改租赁时,仅ForeignKey显示与当前用户匹配的租赁.该ForeignKey字段不会显示在表单上.

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

到目前为止这听起来是否可行,或者我应该向不同的方向发展?


并发症

现在,这是棘手的部分; 我不知道如何处理这个问题.让我们说一个Rental可以有很多"RentalPhotos".RentalPhoto有一个ForeignKeyRental.用户应该能够将照片添加到自己的租借中.但是,这些照片没有用户ForeignKey,因此无法直接找出谁拥有该照片.

这可以通过框架中的一些技巧来解决,ForeignKey直到找到一个带有ForeignKey用户的对象?或者我应该采取简单的方法,并给予RentalPhoto(以及其他所有"属于" Rental)ForeignKey适当的auth.User?第二种方法会招致不必要的冗余,第一种方法可能需要不必要的处理开销......

如果我完全误入歧途,请毫不犹豫地指出我正确的方向.在此先感谢您的帮助.

Anu*_*yal 22

我只是为每个模型添加一个方法is_owned_by(user),由模型决定它是否由该用户拥有.在大多数情况下,is_owned_by可以是基础模型类中的通用函数,您可以在特殊情况下调整它.例如

class RentalPhoto(BaseModel):
    def is_owned_by(self, user):
        return self.rental.is_owned_by(user)
Run Code Online (Sandbox Code Playgroud)

这是通用的,并且明确表示您将完全控制事物的行为方式.

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

class Rental(models.Model):
    # ...
    class Meta:
        permissions = (
            ("can_edit_any", "Can edit any rentals"),
        )
Run Code Online (Sandbox Code Playgroud)

我认为不是为anyand 添加两个权限own,而是应该只添加own权限,因此每个对象已经具有can_edit可以处理的对象,因为用户只能编辑他的对象,如果用户有权限,则can_edit_any只允许他编辑所有对象

使用这个我们可以通过添加自定义后端来扩展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
Run Code Online (Sandbox Code Playgroud)

这是一个非常快速的实现,实际上你可以扩展权限对象以检查它是否需要和对象,例如,permission.is_per_object而不是粗略的字符串搜索,但如果你有标准的名称,它也应该工作