我是Tastypie(和Django)的新手,并且在我的应用程序的api中遇到了循环多对多关系的问题。
我有3个模型RiderProfile
,Ride
和RideMemebership
。 RiderProfilea
可以属于多个Rides
,Rides
可以有多个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)
当我获取RiderProfile
或Ride
(列表或详细信息)时,我收到一个递归错误,因为模型无限地获取它们。我已经尝试使用RelationalField.use_in
参数,这与我想要完成的事情非常接近 - 因为它可以根据请求是针对列表还是详细信息来阻止包含字段。但是,我试图根据调用的端点删除资源字段。
例如,/rides
的请求:
我想列出所有涉及的RiderProfile
项目,但没有Ride
列表。
同样,请求/riders
:
我希望列出Ride
的所有RiderProfile
项,但不包含Rider
列表。
建议的解决方案是什么?我一直在玩dehyrdate
周期,但我正在努力修改相关资源的集合。我还阅读了有关为Rides和Riders使用多个ModelResources的答案。是否有推荐的方法来实现这一目标?
提前感谢您的建议!
更新
我添加了额外的ModelResources
以用于每个端点(RiderProfileForRideResource
和RideForRiderProfileResource
),并且它正在运行。我不确定这是最好的方法。它创建了我不想公开的额外端点。有关更好方法的想法吗?
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'
答案 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)