我试图自学Django和Django Rest Framework,但我很难理解对象所有权是如何定义的。
我想使用默认用户模型应用DRF文档中给定的自定义"IsOwnerOrReadOnly"权限。我的目标是:用户将能够在自己的帐户中放置/修补/删除信息,但不能更改任何其他用户的信息。
我的用户序列化程序:
class UserSerializer(serializers.ModelSerializer):
rides = serializers.PrimaryKeyRelatedField(many = True, queryset = Ride.objects.all())
class Meta:
model = User
fields = [
'pk',
'username',
'first_name',
'last_name',
'email',
'password',
'rides'
]
write_only_fields = ['password']
read_only_fields = ['pk', 'username']
IsOwnerOrReadOnly
代码:
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
线路return obj.owner == request.user
出现问题。它总是返回AttributeError: 'User' object has no attribute 'owner’
。为什么用户的"所有者"不是用户本身?我如何说"owner=this object"以便我的权限类工作?
后续问题:我想最终扩展默认的User模型,添加更多的字段。如果我通过继承AbstractBaseUser
创建了一个新的用户模型,我的权限还会起作用吗?(我刚开始学习Django,所以我不完全确定创建新用户模型的过程是什么。但我认为最好提一下,以防这会改变我定义权限的方式。)
您得到错误是因为没有像所有模型的所有者这样抽象的概念。您必须在模型中定义对象和用户之间的关系,并将其应用于每个模型的权限中。
在这种情况下,你需要确保用户正在尝试修改他自己的用户对象,这样你就可以这样做:
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj == request.user
因此,从本质上讲,这只适用于User模型,您必须根据模型与用户的关系将其扩展到适用于其他模型。
您可能希望为每个资源定义不同的权限类,而不是试图将所有逻辑放在同一权限类中。
至于您关于扩展用户模型的问题。文档中的这一页解释了扩展现有用户模型的不同方法,基本上是从AbstractUser
或AbstractbaseUser
扩展。Django权限框架在针对这些基类实现时仍然可以工作。
但是请记住,DRF权限类与Django权限不同。您可以使用Django权限在权限类中实现逻辑,但它们可以在没有权限的情况下实现。
根据评论编辑
如果您有一个拥有者的Ride
模型,您可以这样做来组合它们。
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
if isinstance(obj, Ride):
return obj.owner == request.user
return obj == request.user
所有权
假设有一个Model A
。要定义所有权,您需要在Model A
中创建一个指向User
模型的字段。你可以很容易地做到这一点。确保使用django.contrib.auth.get_user_model
进行相同操作。
从API获取所属对象的列表
当涉及到获取经过身份验证的用户(request.user
)拥有的对象列表时,您正在考虑创建一个过滤器。要做到这一点,有两种方法:
- 创建一个筛选器类并在其中使用
generic views
。这更具可扩展性。我在drfaddons.filters.IsOwnerFilterBackend
中也做过同样的事情。这是源代码 - 覆盖每个API类中的
def filter_queryset(self, queryset)
确保检索/更新/删除
这一次,您希望确保正在应用权限检查。在这里,您将希望从您正在执行的permissions.BasePermission
实现has_object_permission
和has_permission
。
通常,您需要同时使用filtering
和permission
检查。
在整个项目中实施
要在整个项目中实现这一点,您需要在settings.py
的REST_FRAMEWORK
配置中将filter
和permission
设置为默认值。您还需要确保每个模型中都有一个所有者字段(最好使用相同的名称)。(检查Abstract
型号)。
我在我的所有项目中都做了同样的事情,因此,我创建了一个相同的包。检查DRF插件。您也可以通过pip:pip install drfaddons
安装它。它将完成上述所有任务。