Tastypie授权和ToManyField

时间:2015-11-18 00:52:53

标签: python django rest tastypie

我正在尝试实现包含ToManyField的资源,但我希望ToManyField返回的对象受到请求用户的限制。

我尝试了以下内容,但无济于事。

from django.db import models
from my_project.apps.my_app.models import MyUser
from tastypie.authorization import Authorization
from tastypie.resources import ModelResource
from tastypie import fields

###
# MODELS
###
class TieFighter(models.Model):
    pilot = models.ForeignKey(MyUser)
    fighter_class = models.CharField(max_length=200, blank=True, null=True, default='Interceptor')
    squadron = models.ForeignKey(Squadron, related_name='tie_fighters')

class Squadron(models.Model):
    name = models.CharField(max_length=200, blank=True, null=True)

###
# AUTHORIZATION
###
class TieFighterAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        return object_list.filter(pilot=bundle.request.user)

    def read_detail(self, object_list, bundle):
        return bundle.obj.pilot == bundle.request.user

###
# RESOURCES
###
class TieFighterResource(ModelResource):
    class Meta:
        authorization = TieFighterAuthorization()
        queryset = TieFighter.objects.all()
        allowed_methods = ['get']
        resource_name = 'tie_fighters'

class SquadronResource(ModelResource):
    class Meta:
        authorization = Authorization()
        queryset = Squadron.objects.all()
        allowed_methods = ['get']
        resource_name = 'squadrons'

    tie_fighters = fields.ToManyField(TieFighterResource, null=True, full=True, attribute='tie_fighters')

请注意,我想过滤的pilot关系仅存在于TieFighter中。因此,我为TieFighterResource创建了一个特殊的Authorization子类,强制该资源仅返回其导频与请求用户匹配的领带战斗机。这在我直接调用TieFighterResource端点时有效。但是当我打电话给SquadronResource时,约束就消失了;无论飞行员/请求用户是谁,都会列出该中队内的所有战斗机。

请注意:我想在每个Squadron上过滤掉TieFighter,但仍会返回所有Squadron。也就是说,我不希望我从TieFighter过滤掉,以防止用户看到Squadrontie_fighter关系为空{/ strong>

建议?

2 个答案:

答案 0 :(得分:0)

read_list过滤tie_fighters__pilot

read_detail中抓取所有fie_fighters并按pilot过滤。

class SquadronAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        return object_list.filter(tie_fighters__pilot=bundle.request.user)

    def read_detail(self, object_list, bundle):
        return bundle.obj.tie_fighters.all().filter(pilot=bundle.request.user).count() <> 0

答案 1 :(得分:0)

以下是我解决问题的方法。您可以通过传入一个callable作为命名参数attribute来过滤TastyPie中的关系字段。另见:https://stackoverflow.com/a/20035610/1387495

from tastypie.bundle import Bundle

'''
Enforce the TieFighterResource's ACL.
'''
def enforce_acl(bundle):
    res = TieFighterResource()
    new_bundle = Bundle(request=bundle.request)
    objs = res.obj_get_list(new_bundle)
    return objs

class SquadronResource(ModelResource):    
    ...        
    tie_fighters = fields.ToManyField(TieFighterResource, null=True, full=True, attribute=enforce_acl)

理想情况下,这将内置于TastyPie;我认为这是一个公平的假设,即您传递到ToManyField的资源的授权逻辑将限制字段的结果集,而无需任何其他配置。我有空的时候会创建一个拉取请求。