如何根据请求方式设置不同的权限?
How to set different permissions depending on the request method?
我正在为一些投票创建 API。我需要作者是唯一可以查看投票的人,但经过身份验证的用户可以查看投票、问题和 post 票。作者只是用户的一个实例,就像选民一样。
我正在使用 Djoser 来提供身份验证 API、模型序列化程序,并在 CBV 和视图集之间打破我的想法。
这是我的模型,如果对您有帮助的话。
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
import datetime
User = get_user_model()
class Poll(models.Model):
title = models.CharField(max_length=200, verbose_name="Naslov ankete")
description = models.TextField(verbose_name="Opis ankete")
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="polls", verbose_name="Autor")
class Meta:
verbose_name = "Anketa"
verbose_name_plural = "Ankete"
def __str__(self):
return self.title
class Question(models.Model):
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="questions", verbose_name="Anketa")
question_text = models.CharField(max_length=200, verbose_name="Tekst pitanja")
pub_date = models.DateTimeField(verbose_name="Datum objavljivanja")
class Meta:
ordering = ["pub_date", "question_text"]
verbose_name = "Pitanje"
verbose_name_plural = "Pitanja"
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
def verbose_question_text(self):
return f"Pitanje: {self.question_text}"
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices", verbose_name="Pitanje")
choice_text = models.CharField(max_length=200, verbose_name="Tekst opcije")
# votes = models.IntegerField(default=0, verbose_name="Glasovi")
class Meta:
ordering = ["-votes", "pk"]
verbose_name = "Opcija"
verbose_name_plural = "Opcije"
def __str__(self):
return self.choice_text
class Vote(models.Model):
choice = models.ForeignKey(Choice, on_delete=models.CASCADE, related_name="votes", verbose_name="Opcija")
def __str__(self):
return self.choice.choice_text
P. S.:如果你觉得投票可以用更好的方式解决,也请提出来。
我认为您可以通过创建自定义权限(从 IsAuthenticated class 扩展)和覆盖方法 has_object_permission
、see documentation.
来实现
from rest_framework.permissions import IsAuthenticated
class AuthorFullAccessUserPostOnly(IsAuthenticated):
def has_object_permission(self, request, view, obj):
if request.method == "POST":
return True
# This part better to implement with query
# Also, it will work only for Vote object.
# You need to extend this method if you are going to use for another objects
return request.user == obj.choice.question.poll.author
您可以为每个视图(或视图集)创建权限 class,或者根据对象类型扩展此权限
如果您想对不同的请求方法使用不同的条件,您可以使用某种逻辑
class PoolPermissions(IsAuthenticated):
def has_object_permission(self, request, view, obj):
if request.method == "POST":
self.has_post_object_permission(request, view, obj)
elif request.method == "GET":
self.has_get_object_permission(request, view, obj)
elif request.method == "PUT":
self.has_put_object_permission(request, view, obj)
# etc.
...
def has_get_object_permission(self, request, view, obj):
# your logic
pass
def has_post_object_permission(self, request, view, obj):
# your logic
pass
def has_put_object_permission(self, request, view, obj):
# your logic
pass
我正在为一些投票创建 API。我需要作者是唯一可以查看投票的人,但经过身份验证的用户可以查看投票、问题和 post 票。作者只是用户的一个实例,就像选民一样。 我正在使用 Djoser 来提供身份验证 API、模型序列化程序,并在 CBV 和视图集之间打破我的想法。
这是我的模型,如果对您有帮助的话。
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
import datetime
User = get_user_model()
class Poll(models.Model):
title = models.CharField(max_length=200, verbose_name="Naslov ankete")
description = models.TextField(verbose_name="Opis ankete")
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="polls", verbose_name="Autor")
class Meta:
verbose_name = "Anketa"
verbose_name_plural = "Ankete"
def __str__(self):
return self.title
class Question(models.Model):
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="questions", verbose_name="Anketa")
question_text = models.CharField(max_length=200, verbose_name="Tekst pitanja")
pub_date = models.DateTimeField(verbose_name="Datum objavljivanja")
class Meta:
ordering = ["pub_date", "question_text"]
verbose_name = "Pitanje"
verbose_name_plural = "Pitanja"
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
def verbose_question_text(self):
return f"Pitanje: {self.question_text}"
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices", verbose_name="Pitanje")
choice_text = models.CharField(max_length=200, verbose_name="Tekst opcije")
# votes = models.IntegerField(default=0, verbose_name="Glasovi")
class Meta:
ordering = ["-votes", "pk"]
verbose_name = "Opcija"
verbose_name_plural = "Opcije"
def __str__(self):
return self.choice_text
class Vote(models.Model):
choice = models.ForeignKey(Choice, on_delete=models.CASCADE, related_name="votes", verbose_name="Opcija")
def __str__(self):
return self.choice.choice_text
P. S.:如果你觉得投票可以用更好的方式解决,也请提出来。
我认为您可以通过创建自定义权限(从 IsAuthenticated class 扩展)和覆盖方法 has_object_permission
、see documentation.
from rest_framework.permissions import IsAuthenticated
class AuthorFullAccessUserPostOnly(IsAuthenticated):
def has_object_permission(self, request, view, obj):
if request.method == "POST":
return True
# This part better to implement with query
# Also, it will work only for Vote object.
# You need to extend this method if you are going to use for another objects
return request.user == obj.choice.question.poll.author
您可以为每个视图(或视图集)创建权限 class,或者根据对象类型扩展此权限
如果您想对不同的请求方法使用不同的条件,您可以使用某种逻辑
class PoolPermissions(IsAuthenticated):
def has_object_permission(self, request, view, obj):
if request.method == "POST":
self.has_post_object_permission(request, view, obj)
elif request.method == "GET":
self.has_get_object_permission(request, view, obj)
elif request.method == "PUT":
self.has_put_object_permission(request, view, obj)
# etc.
...
def has_get_object_permission(self, request, view, obj):
# your logic
pass
def has_post_object_permission(self, request, view, obj):
# your logic
pass
def has_put_object_permission(self, request, view, obj):
# your logic
pass