有条件限制TastyPie中的相关资源数据

时间:2015-02-16 20:37:02

标签: django tastypie

我是Tastypie(和Django)的新手,并且在我的应用程序的api中遇到了循环多对多关系的问题。

我有3个模型RiderProfileRideRideMemebershipRiderProfilea可以属于多个RidesRides可以有多个RiderProfile。多对多关系由RideMembership调解。我的模型看起来像:

class RiderProfile(models.Model):
    user = models.OneToOneField(User)
    age = models.IntegerField(max_length=2)
    rides = models.ManyToManyField('riderapp.Ride', through="RideMembership")

    def __unicode__(self):
        return self.user.get_username()


class Ride(models.Model):
    name = models.CharField(max_length=64)
    riders = models.ManyToManyField(RiderProfile, through="RideMembership")

    def __unicode__(self):
        return self.name

class RideMembership(models.Model):
    rider = models.ForeignKey(RiderProfile)
    ride = models.ForeignKey(Ride)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

    def __unicode__(self):
        return self.rider.user.get_username() + ' to ' + self.ride.name()

我的TastyPie资源如下:

class UserResource(ModelResource):
    ...

class RideResource(ModelResource):
    class Meta:
        queryset = Ride.objects.all()
        resource_name = 'rides'

    riders = fields.ToManyField('riderapp.api.RiderProfileResource', 'riders', full=True)

class RiderProfileResource(ModelResource):
    class Meta:
        queryset = RiderProfile.objects.all()
        resource_name = 'riders'

    user = fields.ForeignKey(UserResource, 'user', full=True)
    rides = fields.ToManyField('riderapp.api.RideResource', 'rides', full=True)     

当我获取RiderProfileRide(列表或详细信息)时,我收到一个递归错误,因为模型无限地获取它们。我已经尝试使用RelationalField.use_in参数,这与我想要完成的事情非常接近 - 因为它可以根据请求是针对列表还是详细信息来阻止包含字段。但是,我试图根据调用的端点删除资源字段。

例如,/rides的请求: 我想列出所有涉及的RiderProfile项目,但没有Ride列表。

同样,请求/riders: 我希望列出Ride的所有RiderProfile项,但不包含Rider列表。

建议的解决方案是什么?我一直在玩dehyrdate周期,但我正在努力修改相关资源的集合。我还阅读了有关为Rides和Riders使用多个ModelResources的答案。是否有推荐的方法来实现这一目标?

提前感谢您的建议!

更新

我添加了额外的ModelResources以用于每个端点(RiderProfileForRideResourceRideForRiderProfileResource),并且它正在运行。我不确定这是最好的方法。它创建了我不想公开的额外端点。有关更好方法的想法吗?

class UserResource(ModelResource):
    ...

class RideResource(ModelResource):
    class Meta:
        queryset = Ride.objects.all()
        resource_name = 'rides'

    riders = fields.ToManyField('riderapp.api.RiderProfileForRideResource', 'riders', full=True)

class RideForRiderProfileResource(ModelResource):
    class Meta:
        queryset = Ride.objects.all()
        resource_name = 'rides_for_riders'

class RiderProfileResource(ModelResource):
    class Meta:
        queryset = RiderProfile.objects.all()
        resource_name = 'riders'

    user = fields.ForeignKey(UserResource, 'user', full=True)
    rides = fields.ToManyField('riderapp.api.RideForRiderProfileResource', 'rides', full=True)

class RiderProfileForRideResource(ModelResource):
    class Meta:
        queryset = RiderProfile.objects.all()
        resource_name = 'riders_for_ride'

    user = fields.ForeignKey(UserResource, 'user', full=True)

class RideMembershipResource(ModelResource):
    class Meta:
        queryset = RideMembership.objects.all()
        resource_name = 'rider_membership' 

2 个答案:

答案 0 :(得分:2)

这可能不是最干净的一种方法,但您可以尝试通过检查api的资源uri路径,在脱水循环中删除骑手打电话给你做了

    class RideResource(ModelResource):
       class Meta:
           queryset = Ride.objects.all()
           resource_name = 'rides'

       riders = fields.ToManyField('riderapp.api.RiderProfileResource', 'riders', full=True)

       def dehydrate(self, bundle):
            # You make api call to 'riders' and are dehydrating related source RideResource. Path should be of the form API/app_name/riders
            # When call made directly to this resource then uri path will be API/app_name/rides and if statement will not be entered
            if 'riders' in bundle.request.path:
                  del bundle.data['riders']

,反之亦然。

答案 1 :(得分:2)

您可以将callable用于资源字段的use_in属性,而不是覆盖脱水。

def riders_check(bundle):
    return 'riders' in bundle.request.path

类似的东西,

riders = fields.ToManyField('riderapp.api.RiderProfileForRideResource', 'riders', full=True, use_in=riders_check)