我有一个非常简单的嵌套模型。
class Game(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
user = models.ForeignKey(User)
class Activity(models.Model):
game = models.ForeignKey(Game, related_name = 'activities')
type = models.CharField(max_length=4)
score = models.DecimalField(max_digits=3, decimal_places=2)
我可以通过管理员创建对象,并且运行顺利。然后我使用 TastyPie 创建了一个 API。我的资源如下所示:
class GameResource(ModelResource):
user = fields.ToOneField(UserResource, 'user')
app = fields.ToOneField(AppResource, 'app')
activities = fields.ToManyField('api.resources.ActivityResource', 'activities', full=True, related_name='activity')
class Meta:
queryset = Game.objects.all()
resource_name = 'games'
list_allowed_methods = ['get','post']
detail_allowed_methods = ['get','put','post','delete']
authentication = ApiKeyTokenAuthentication()
authorization = Authorization()
serializer = CustomJSONSerializer(formats=['json'])
def apply_authorization_limits(self, request, object_list):
return object_list.filter(user=request.user)
def obj_create(self, bundle, request=None, **kwargs):
requestApp = App.objects.get(api_key=request.api_key)
return super(GameResource, self).obj_create(bundle, request, app=requestApp)
def get_object_list(self, request):
return super(GameResource, self).get_object_list(request).filter(app__api_key=request.api_key)
class ActivityResource(ModelResource):
game = fields.ForeignKey(GameResource, 'game')
class Meta:
queryset = Activity.objects.all()
resource_name = 'activities'
list_allowed_methods = ['get','post']
detail_allowed_methods = ['get','put','post','delete']
authentication = ApiKeyTokenAuthentication()
authorization = Authorization()
serializer = CustomJSONSerializer(formats=['json'])
def apply_authorization_limits(self, request, object_list):
return object_list.filter(game__user=request.user)
def obj_create(self, bundle, request=None, **kwargs):
return super(ActivityResource, self).obj_create(bundle, request)
def get_object_list(self, request):
return super(ActivityResource, self).get_object_list(request).filter(game__app__api_key=request.api_key)
我从应用程序中发布了这本字典,其中包含游戏中嵌套的活动。
{
name = "Monte";
description = "To search for the holy grail.";
user = "/api/v1/users/2/";
activities = (
{
type = "eggs";
score = "0.50";
}
);
}
结果是在数据库中创建了游戏,但是当 TastyPie 尝试创建嵌套的 Activity 对象时,它吐出一个错误。该错误表示当它尝试获取活动列表时,它无法找到与 api_key 匹配的活动。我不明白它为什么要尝试获取对象,并且我不明白如果它使用发送请求的应用程序正确创建游戏,则 NoneType 来自哪里。您可以看到我找到了与 request.api_key 匹配的应用程序并将其设置为游戏的应用程序。
"error_message": "'NoneType' object has no attribute 'api_key'"
super(ActivityResource, self).get_object_list(request).filter(game__app__api_key=request.api_key)\n\nAttributeError: 'NoneType' object has no attribute 'api_key'\n"
我错过了什么?我的资源和获取活动的方式有问题吗?
作为旁注......我可以发布一本字典:
{
game = "/api/v1/games/2/"
type = "eggs";
score = "0.50";
}
当我将其发布到活动时,它会正确创建活动。当我通过 API 获取活动时,它看起来就像那样。
所以问题不在于创建活动,而在于创建嵌套在游戏中的活动。
更新:
我放了一些断点,发现在resource_from_data中它正在调用obj_update而不是在请求中发送,因此request = NoneType。这是 TastyPie 中的错误吗?
def resource_from_data(self, fk_resource, data, request=None, related_obj=None, related_name=None):
"""
Given a dictionary-like structure is provided, a fresh related
resource is created using that data.
"""
# Try to hydrate the data provided.
data = dict_strip_unicode_keys(data)
fk_bundle = fk_resource.build_bundle(data=data, request=request)
if related_obj:
fk_bundle.related_obj = related_obj
fk_bundle.related_name = related_name
# We need to check to see if updates are allowed on the FK
# resource. If not, we'll just return a populated bundle instead
# of mistakenly updating something that should be read-only.
if not fk_resource.can_update():
return fk_resource.full_hydrate(fk_bundle)
try:
return fk_resource.obj_update(fk_bundle, request, **data)
except NotFound:
try:
# Attempt lookup by primary key
lookup_kwargs = dict((k, v) for k, v in data.iteritems() if getattr(fk_resource, k).unique)
if not lookup_kwargs:
raise NotFound()
return fk_resource.obj_update(fk_bundle, **lookup_kwargs)
except NotFound:
return fk_resource.full_hydrate(fk_bundle)
except MultipleObjectsReturned:
return fk_resource.full_hydrate(fk_bundle)